xref: /titanic_54/usr/src/lib/libkmf/libkmf/common/pem_encode.c (revision d00756ccb34596a328f8a15d1965da5412d366d0)
199ebb4caSwyllys /*
2*d00756ccSwyllys  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
399ebb4caSwyllys  * Use is subject to license terms.
499ebb4caSwyllys  */
599ebb4caSwyllys 
699ebb4caSwyllys #pragma ident	"%Z%%M%	%I%	%E% SMI"
799ebb4caSwyllys 
899ebb4caSwyllys /*
999ebb4caSwyllys  * Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
1099ebb4caSwyllys  * All rights reserved.
1199ebb4caSwyllys  *
1299ebb4caSwyllys  * This package is an SSL implementation written
1399ebb4caSwyllys  * by Eric Young (eay@cryptsoft.com).
1499ebb4caSwyllys  * The implementation was written so as to conform with Netscapes SSL.
1599ebb4caSwyllys  *
1699ebb4caSwyllys  * This library is free for commercial and non-commercial use as long as
1799ebb4caSwyllys  * the following conditions are aheared to.  The following conditions
1899ebb4caSwyllys  * apply to all code found in this distribution, be it the RC4, RSA,
1999ebb4caSwyllys  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
2099ebb4caSwyllys  * included with this distribution is covered by the same copyright terms
2199ebb4caSwyllys  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
2299ebb4caSwyllys  *
2399ebb4caSwyllys  * Copyright remains Eric Young's, and as such any Copyright notices in
2499ebb4caSwyllys  * the code are not to be removed.
2599ebb4caSwyllys  * If this package is used in a product, Eric Young should be given attribution
2699ebb4caSwyllys  * as the author of the parts of the library used.
2799ebb4caSwyllys  * This can be in the form of a textual message at program startup or
2899ebb4caSwyllys  * in documentation (online or textual) provided with the package.
2999ebb4caSwyllys  *
3099ebb4caSwyllys  * Redistribution and use in source and binary forms, with or without
3199ebb4caSwyllys  * modification, are permitted provided that the following conditions
3299ebb4caSwyllys  * are met:
3399ebb4caSwyllys  * 1. Redistributions of source code must retain the copyright
3499ebb4caSwyllys  *    notice, this list of conditions and the following disclaimer.
3599ebb4caSwyllys  * 2. Redistributions in binary form must reproduce the above copyright
3699ebb4caSwyllys  *    notice, this list of conditions and the following disclaimer in the
3799ebb4caSwyllys  *    documentation and/or other materials provided with the distribution.
3899ebb4caSwyllys  * 3. All advertising materials mentioning features or use of this software
3999ebb4caSwyllys  *    must display the following acknowledgement:
4099ebb4caSwyllys  *    "This product includes cryptographic software written by
4199ebb4caSwyllys  *     Eric Young (eay@cryptsoft.com)"
4299ebb4caSwyllys  *    The word 'cryptographic' can be left out if the rouines from the library
4399ebb4caSwyllys  *    being used are not cryptographic related :-).
4499ebb4caSwyllys  * 4. If you include any Windows specific code (or a derivative thereof) from
4599ebb4caSwyllys  *    the apps directory (application code) you must include an acknowledgement:
4699ebb4caSwyllys  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
4799ebb4caSwyllys  *
4899ebb4caSwyllys  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4999ebb4caSwyllys  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5099ebb4caSwyllys  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5199ebb4caSwyllys  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
5299ebb4caSwyllys  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5399ebb4caSwyllys  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5499ebb4caSwyllys  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5599ebb4caSwyllys  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5699ebb4caSwyllys  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5799ebb4caSwyllys  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5899ebb4caSwyllys  * SUCH DAMAGE.
5999ebb4caSwyllys  *
6099ebb4caSwyllys  * The licence and distribution terms for any publically available version or
6199ebb4caSwyllys  * derivative of this code cannot be changed.  i.e. this code cannot simply be
6299ebb4caSwyllys  * copied and put under another distribution licence
6399ebb4caSwyllys  * [including the GNU Public Licence.]
6499ebb4caSwyllys  */
6599ebb4caSwyllys 
6699ebb4caSwyllys /* pem_encode.c - PEM encoding routines */
6799ebb4caSwyllys 
6899ebb4caSwyllys #include <stdlib.h>
6999ebb4caSwyllys #include <strings.h>
7099ebb4caSwyllys #include <sys/types.h>
7199ebb4caSwyllys #include <kmfapi.h>
7299ebb4caSwyllys #include <pem_encode.h>
7399ebb4caSwyllys 
7499ebb4caSwyllys static unsigned char data_bin2ascii[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\
7599ebb4caSwyllys abcdefghijklmnopqrstuvwxyz0123456789+/";
7699ebb4caSwyllys 
7799ebb4caSwyllys static unsigned char data_ascii2bin[128] = {
7899ebb4caSwyllys 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
7999ebb4caSwyllys 	0xFF, 0xE0, 0xF0, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF,
8099ebb4caSwyllys 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
8199ebb4caSwyllys 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
8299ebb4caSwyllys 	0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
8399ebb4caSwyllys 	0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F,
8499ebb4caSwyllys 	0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
8599ebb4caSwyllys 	0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
8699ebb4caSwyllys 	0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
8799ebb4caSwyllys 	0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
8899ebb4caSwyllys 	0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
8999ebb4caSwyllys 	0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
9099ebb4caSwyllys 	0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
9199ebb4caSwyllys 	0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
9299ebb4caSwyllys 	0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
9399ebb4caSwyllys 	0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
9499ebb4caSwyllys };
9599ebb4caSwyllys 
9699ebb4caSwyllys #define	conv_bin2ascii(a)	(data_bin2ascii[(a)&0x3f])
9799ebb4caSwyllys #define	conv_ascii2bin(a)	(data_ascii2bin[(a)&0x7f])
9899ebb4caSwyllys 
9999ebb4caSwyllys 
10099ebb4caSwyllys void
PEM_EncodeInit(PEM_ENCODE_CTX * ctx)10199ebb4caSwyllys PEM_EncodeInit(PEM_ENCODE_CTX *ctx)
10299ebb4caSwyllys {
10399ebb4caSwyllys 	ctx->length = 48;
10499ebb4caSwyllys 	ctx->num = 0;
10599ebb4caSwyllys 	ctx->line_num = 0;
10699ebb4caSwyllys }
10799ebb4caSwyllys 
10899ebb4caSwyllys int
PEM_EncodeBlock(unsigned char * t,const unsigned char * f,int dlen)10999ebb4caSwyllys PEM_EncodeBlock(unsigned char *t, const unsigned char *f, int dlen)
11099ebb4caSwyllys {
11199ebb4caSwyllys 	int i, ret = 0;
11299ebb4caSwyllys 	unsigned long l;
11399ebb4caSwyllys 
11499ebb4caSwyllys 	for (i = dlen; i > 0; i -= 3) {
11599ebb4caSwyllys 		if (i >= 3) {
11699ebb4caSwyllys 			l = (((unsigned long)f[0])<<16L)|
11799ebb4caSwyllys 			    (((unsigned long)f[1])<< 8L)|f[2];
11899ebb4caSwyllys 			*(t++) = conv_bin2ascii(l>>18L);
11999ebb4caSwyllys 			*(t++) = conv_bin2ascii(l>>12L);
12099ebb4caSwyllys 			*(t++) = conv_bin2ascii(l>> 6L);
12199ebb4caSwyllys 			*(t++) = conv_bin2ascii(l);
12299ebb4caSwyllys 		} else {
12399ebb4caSwyllys 			l = ((unsigned long)f[0])<<16L;
12499ebb4caSwyllys 			if (i == 2)
12599ebb4caSwyllys 				l |= ((unsigned long)f[1]<<8L);
12699ebb4caSwyllys 
12799ebb4caSwyllys 			*(t++) = conv_bin2ascii(l>>18L);
12899ebb4caSwyllys 			*(t++) = conv_bin2ascii(l>>12L);
12999ebb4caSwyllys 			*(t++) = (i == 1)?'=':conv_bin2ascii(l>> 6L);
13099ebb4caSwyllys 			*(t++) = '=';
13199ebb4caSwyllys 		}
13299ebb4caSwyllys 		ret += 4;
13399ebb4caSwyllys 		f += 3;
13499ebb4caSwyllys 	}
13599ebb4caSwyllys 
13699ebb4caSwyllys 	*t = '\0';
13799ebb4caSwyllys 	return (ret);
13899ebb4caSwyllys }
13999ebb4caSwyllys 
14099ebb4caSwyllys void
PEM_EncodeUpdate(PEM_ENCODE_CTX * ctx,unsigned char * out,int * outl,unsigned char * in,int inl)14199ebb4caSwyllys PEM_EncodeUpdate(PEM_ENCODE_CTX *ctx, unsigned char *out, int *outl,
14299ebb4caSwyllys 	unsigned char *in, int inl)
14399ebb4caSwyllys {
14499ebb4caSwyllys 	int i, j;
14599ebb4caSwyllys 	unsigned int total = 0;
14699ebb4caSwyllys 
14799ebb4caSwyllys 	*outl = 0;
14899ebb4caSwyllys 	if (inl == 0)
14999ebb4caSwyllys 		return;
15099ebb4caSwyllys 	if ((ctx->num+inl) < ctx->length) {
15199ebb4caSwyllys 		(void) memcpy(&(ctx->enc_data[ctx->num]), in, inl);
15299ebb4caSwyllys 		ctx->num += inl;
15399ebb4caSwyllys 		return;
15499ebb4caSwyllys 	}
15599ebb4caSwyllys 	if (ctx->num != 0) {
15699ebb4caSwyllys 		i = ctx->length-ctx->num;
15799ebb4caSwyllys 		(void) memcpy(&(ctx->enc_data[ctx->num]), in, i);
15899ebb4caSwyllys 		in += i;
15999ebb4caSwyllys 		inl -= i;
16099ebb4caSwyllys 		j = PEM_EncodeBlock(out, ctx->enc_data, ctx->length);
16199ebb4caSwyllys 		ctx->num = 0;
16299ebb4caSwyllys 		out += j;
16399ebb4caSwyllys 		*(out++) = '\n';
16499ebb4caSwyllys 		*out = '\0';
16599ebb4caSwyllys 		total = j+1;
16699ebb4caSwyllys 	}
16799ebb4caSwyllys 
16899ebb4caSwyllys 	while (inl >= ctx->length) {
16999ebb4caSwyllys 		j = PEM_EncodeBlock(out, in, ctx->length);
17099ebb4caSwyllys 		in += ctx->length;
17199ebb4caSwyllys 		inl -= ctx->length;
17299ebb4caSwyllys 		out += j;
17399ebb4caSwyllys 		*(out++) = '\n';
17499ebb4caSwyllys 		*out = '\0';
17599ebb4caSwyllys 		total += j+1;
17699ebb4caSwyllys 	}
17799ebb4caSwyllys 
17899ebb4caSwyllys 	if (inl != 0)
17999ebb4caSwyllys 		(void) memcpy(&(ctx->enc_data[0]), in, inl);
18099ebb4caSwyllys 	ctx->num = inl;
18199ebb4caSwyllys 	*outl = total;
18299ebb4caSwyllys }
18399ebb4caSwyllys 
18499ebb4caSwyllys void
PEM_EncodeFinal(PEM_ENCODE_CTX * ctx,unsigned char * out,int * outl)18599ebb4caSwyllys PEM_EncodeFinal(PEM_ENCODE_CTX *ctx, unsigned char *out, int *outl)
18699ebb4caSwyllys {
18799ebb4caSwyllys 	unsigned int ret = 0;
18899ebb4caSwyllys 
18999ebb4caSwyllys 	if (ctx->num != 0) {
19099ebb4caSwyllys 		ret = PEM_EncodeBlock(out, ctx->enc_data, ctx->num);
19199ebb4caSwyllys 		out[ret++] = '\n';
19299ebb4caSwyllys 		out[ret] = '\0';
19399ebb4caSwyllys 		ctx->num = 0;
19499ebb4caSwyllys 	}
19599ebb4caSwyllys 	*outl = ret;
19699ebb4caSwyllys }
19799ebb4caSwyllys 
19899ebb4caSwyllys KMF_RETURN
Der2Pem(KMF_OBJECT_TYPE type,unsigned char * data,int len,unsigned char ** out,int * outlen)19999ebb4caSwyllys Der2Pem(KMF_OBJECT_TYPE type, unsigned char *data,
20099ebb4caSwyllys 	int len, unsigned char **out, int *outlen)
20199ebb4caSwyllys {
20299ebb4caSwyllys 
20399ebb4caSwyllys 
20499ebb4caSwyllys 	int nlen, n, i, j, outl;
20599ebb4caSwyllys 	unsigned char *buf = NULL, *p = NULL;
20699ebb4caSwyllys 	PEM_ENCODE_CTX ctx;
20799ebb4caSwyllys 	char *name = NULL;
20899ebb4caSwyllys 
20999ebb4caSwyllys 	if (data == NULL || len == 0 || out == NULL || outlen == NULL)
21099ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
21199ebb4caSwyllys 
21299ebb4caSwyllys 	if (type == KMF_CERT)
21399ebb4caSwyllys 		name = PEM_STRING_X509;
21499ebb4caSwyllys 	else if (type == KMF_CSR)
21599ebb4caSwyllys 		name = PEM_STRING_X509_REQ;
21699ebb4caSwyllys 	else if (type == KMF_CRL)
21799ebb4caSwyllys 		name = PEM_STRING_X509_CRL;
21899ebb4caSwyllys 	else
21999ebb4caSwyllys 		return (KMF_ERR_BAD_OBJECT_TYPE);
22099ebb4caSwyllys 
22199ebb4caSwyllys 
22299ebb4caSwyllys 	PEM_EncodeInit(&ctx);
22399ebb4caSwyllys 	nlen = strlen(name);
22499ebb4caSwyllys 
22599ebb4caSwyllys 	buf = malloc(PEM_BUFSIZE*8);
22699ebb4caSwyllys 	if (buf == NULL) {
22799ebb4caSwyllys 		return (KMF_ERR_MEMORY);
22899ebb4caSwyllys 	}
22999ebb4caSwyllys 
23099ebb4caSwyllys 	p = buf;
23199ebb4caSwyllys 	(void) memcpy(p, "-----BEGIN ", 11);
23299ebb4caSwyllys 	p += 11;
23399ebb4caSwyllys 	(void) memcpy(p, name, nlen);
23499ebb4caSwyllys 	p += nlen;
23599ebb4caSwyllys 	(void) memcpy(p, "-----\n", 6);
23699ebb4caSwyllys 	p += 6;
23799ebb4caSwyllys 
23899ebb4caSwyllys 	i = j = 0;
23999ebb4caSwyllys 	while (len > 0) {
24099ebb4caSwyllys 		n = (int)((len > (PEM_BUFSIZE*5))?(PEM_BUFSIZE*5):len);
24199ebb4caSwyllys 		PEM_EncodeUpdate(&ctx, p, &outl, &(data[j]), n);
24299ebb4caSwyllys 		i += outl;
24399ebb4caSwyllys 		len -= n;
24499ebb4caSwyllys 		j += n;
24599ebb4caSwyllys 		p += outl;
24699ebb4caSwyllys 	}
24799ebb4caSwyllys 
24899ebb4caSwyllys 	PEM_EncodeFinal(&ctx, p, &outl);
24999ebb4caSwyllys 
25099ebb4caSwyllys 	if (outl > 0)
25199ebb4caSwyllys 		p += outl;
25299ebb4caSwyllys 
25399ebb4caSwyllys 	(void) memcpy(p, "-----END ", 9);
25499ebb4caSwyllys 	p += 9;
25599ebb4caSwyllys 	(void) memcpy(p, name, nlen);
25699ebb4caSwyllys 	p += nlen;
25799ebb4caSwyllys 	(void) memcpy(p, "-----\n", 6);
25899ebb4caSwyllys 	p += 6;
25999ebb4caSwyllys 
26099ebb4caSwyllys 	*out = buf;
26199ebb4caSwyllys 	*outlen = i+outl+nlen*2+11+6+9+6;
26299ebb4caSwyllys 
26399ebb4caSwyllys 	return (KMF_OK);
26499ebb4caSwyllys 
26599ebb4caSwyllys }
26699ebb4caSwyllys 
26799ebb4caSwyllys int
PEM_DecodeBlock(unsigned char * t,const unsigned char * f,int n)26899ebb4caSwyllys PEM_DecodeBlock(unsigned char *t, const unsigned char *f, int n)
26999ebb4caSwyllys {
27099ebb4caSwyllys 	int i, ret = 0, a, b, c, d;
27199ebb4caSwyllys 	unsigned long l;
27299ebb4caSwyllys 
27399ebb4caSwyllys 	/* trim white space from the start of the line. */
27499ebb4caSwyllys 	while ((conv_ascii2bin(*f) == B64_WS) && (n > 0)) {
27599ebb4caSwyllys 		f++;
27699ebb4caSwyllys 		n--;
27799ebb4caSwyllys 	}
27899ebb4caSwyllys 
27999ebb4caSwyllys 	/*
28099ebb4caSwyllys 	 * strip off stuff at the end of the line
28199ebb4caSwyllys 	 * ascii2bin values B64_WS, B64_EOLN, B64_EOLN and B64_EOF
28299ebb4caSwyllys 	 */
28399ebb4caSwyllys 	while ((n > 3) && (B64_NOT_BASE64(conv_ascii2bin(f[n-1]))))
28499ebb4caSwyllys 		n--;
28599ebb4caSwyllys 
28699ebb4caSwyllys 	if (n%4 != 0) {
28799ebb4caSwyllys 		return (-1);
28899ebb4caSwyllys 	}
28999ebb4caSwyllys 
29099ebb4caSwyllys 	for (i = 0; i < n; i += 4) {
29199ebb4caSwyllys 		a = conv_ascii2bin(*(f++));
29299ebb4caSwyllys 		b = conv_ascii2bin(*(f++));
29399ebb4caSwyllys 		c = conv_ascii2bin(*(f++));
29499ebb4caSwyllys 		d = conv_ascii2bin(*(f++));
295fbcec901Shylee 		if ((a & 0x80) || (b & 0x80) ||	(c & 0x80) || (d & 0x80))
29699ebb4caSwyllys 			return (-1);
297fbcec901Shylee 		l = ((((unsigned long)a)<<18L) | (((unsigned long)b)<<12L) |
298fbcec901Shylee 		    (((unsigned long)c)<< 6L) | (((unsigned long)d)));
29999ebb4caSwyllys 		*(t++) = (unsigned char)(l>>16L)&0xff;
30099ebb4caSwyllys 		*(t++) = (unsigned char)(l>> 8L)&0xff;
30199ebb4caSwyllys 		*(t++) = (unsigned char)(l)&0xff;
30299ebb4caSwyllys 		ret += 3;
30399ebb4caSwyllys 	}
30499ebb4caSwyllys 	return (ret);
30599ebb4caSwyllys }
30699ebb4caSwyllys 
30799ebb4caSwyllys void
PEM_DecodeInit(PEM_ENCODE_CTX * ctx)30899ebb4caSwyllys PEM_DecodeInit(PEM_ENCODE_CTX *ctx)
30999ebb4caSwyllys {
31099ebb4caSwyllys 	ctx->length = 30;
31199ebb4caSwyllys 	ctx->num = 0;
31299ebb4caSwyllys 	ctx->line_num = 0;
31399ebb4caSwyllys 	ctx->expect_nl = 0;
31499ebb4caSwyllys }
31599ebb4caSwyllys 
31699ebb4caSwyllys /*
31799ebb4caSwyllys  * -1 for error
31899ebb4caSwyllys  *  0 for last line
31999ebb4caSwyllys  *  1 for full line
32099ebb4caSwyllys  */
32199ebb4caSwyllys int
PEM_DecodeUpdate(PEM_ENCODE_CTX * ctx,unsigned char * out,int * outl,unsigned char * in,int inl)32299ebb4caSwyllys PEM_DecodeUpdate(PEM_ENCODE_CTX *ctx, unsigned char *out, int *outl,
32399ebb4caSwyllys     unsigned char *in, int inl)
32499ebb4caSwyllys {
32599ebb4caSwyllys 	int seof = -1, eof = 0, rv = -1, ret = 0;
32699ebb4caSwyllys 	int i, v, tmp, n, ln, exp_nl;
32799ebb4caSwyllys 	unsigned char *d;
32899ebb4caSwyllys 
32999ebb4caSwyllys 	n = ctx->num;
33099ebb4caSwyllys 	d = ctx->enc_data;
33199ebb4caSwyllys 	ln = ctx->line_num;
33299ebb4caSwyllys 	exp_nl = ctx->expect_nl;
33399ebb4caSwyllys 
33499ebb4caSwyllys 	/* last line of input. */
33599ebb4caSwyllys 	if ((inl == 0) || ((n == 0) && (conv_ascii2bin(in[0]) == B64_EOF))) {
33699ebb4caSwyllys 		rv = 0;
33799ebb4caSwyllys 		goto end;
33899ebb4caSwyllys 	}
33999ebb4caSwyllys 
34099ebb4caSwyllys 	/* We parse the input data */
34199ebb4caSwyllys 	for (i = 0; i < inl; i++) {
34299ebb4caSwyllys 		/* If the current line is > 80 characters, scream alot */
34399ebb4caSwyllys 		if (ln >= 80) {
34499ebb4caSwyllys 			rv = -1;
34599ebb4caSwyllys 			goto end;
34699ebb4caSwyllys 		}
34799ebb4caSwyllys 
34899ebb4caSwyllys 		/* Get char and put it into the buffer */
34999ebb4caSwyllys 		tmp = *(in++);
35099ebb4caSwyllys 		v = conv_ascii2bin(tmp);
35199ebb4caSwyllys 		/* only save the good data :-) */
35299ebb4caSwyllys 		if (!B64_NOT_BASE64(v)) {
35399ebb4caSwyllys 			d[n++] = tmp;
35499ebb4caSwyllys 			ln++;
35599ebb4caSwyllys 		} else if (v == B64_ERROR) {
35699ebb4caSwyllys 			rv = -1;
35799ebb4caSwyllys 			goto end;
35899ebb4caSwyllys 		}
35999ebb4caSwyllys 
36099ebb4caSwyllys 		/*
36199ebb4caSwyllys 		 * have we seen a '=' which is 'definitly' the last
36299ebb4caSwyllys 		 * input line.  seof will point to the character that
36399ebb4caSwyllys 		 * holds it. and eof will hold how many characters to
36499ebb4caSwyllys 		 * chop off.
36599ebb4caSwyllys 		 */
36699ebb4caSwyllys 		if (tmp == '=') {
36799ebb4caSwyllys 			if (seof == -1) seof = n;
36899ebb4caSwyllys 			eof++;
36999ebb4caSwyllys 		}
37099ebb4caSwyllys 
37199ebb4caSwyllys 		if (v == B64_CR) {
37299ebb4caSwyllys 			ln = 0;
37399ebb4caSwyllys 			if (exp_nl)
37499ebb4caSwyllys 				continue;
37599ebb4caSwyllys 		}
37699ebb4caSwyllys 
37799ebb4caSwyllys 		/* eoln */
37899ebb4caSwyllys 		if (v == B64_EOLN) {
37999ebb4caSwyllys 			ln = 0;
38099ebb4caSwyllys 			if (exp_nl) {
38199ebb4caSwyllys 				exp_nl = 0;
38299ebb4caSwyllys 				continue;
38399ebb4caSwyllys 			}
38499ebb4caSwyllys 		}
38599ebb4caSwyllys 		exp_nl = 0;
38699ebb4caSwyllys 
38799ebb4caSwyllys 		/*
38899ebb4caSwyllys 		 * If we are at the end of input and it looks like a
38999ebb4caSwyllys 		 * line, process it.
39099ebb4caSwyllys 		 */
39199ebb4caSwyllys 		if (((i+1) == inl) && (((n&3) == 0) || eof)) {
39299ebb4caSwyllys 			v = B64_EOF;
39399ebb4caSwyllys 			/*
39499ebb4caSwyllys 			 * In case things were given us in really small
39599ebb4caSwyllys 			 * records (so two '=' were given in separate
39699ebb4caSwyllys 			 * updates), eof may contain the incorrect number
39799ebb4caSwyllys 			 * of ending bytes to skip, so let's redo the count
39899ebb4caSwyllys 			 */
39999ebb4caSwyllys 			eof = 0;
40099ebb4caSwyllys 			if (d[n-1] == '=') eof++;
40199ebb4caSwyllys 			if (d[n-2] == '=') eof++;
40299ebb4caSwyllys 			/* There will never be more than two '=' */
40399ebb4caSwyllys 		}
40499ebb4caSwyllys 
40599ebb4caSwyllys 		if ((v == B64_EOF) || (n >= 64)) {
40699ebb4caSwyllys 			/*
40799ebb4caSwyllys 			 * This is needed to work correctly on 64 byte input
40899ebb4caSwyllys 			 * lines.  We process the line and then need to
40999ebb4caSwyllys 			 * accept the '\n'
41099ebb4caSwyllys 			 */
41199ebb4caSwyllys 			if ((v != B64_EOF) && (n >= 64))
41299ebb4caSwyllys 				exp_nl = 1;
41399ebb4caSwyllys 			if (n > 0) {
41499ebb4caSwyllys 				v = PEM_DecodeBlock(out, d, n);
41599ebb4caSwyllys 				if (v < 0) {
41699ebb4caSwyllys 					rv = 0;
41799ebb4caSwyllys 					goto end;
41899ebb4caSwyllys 				}
41999ebb4caSwyllys 				n = 0;
42099ebb4caSwyllys 				ret += (v-eof);
42199ebb4caSwyllys 			} else {
42299ebb4caSwyllys 				eof = 1;
42399ebb4caSwyllys 				v = 0;
42499ebb4caSwyllys 			}
42599ebb4caSwyllys 
42699ebb4caSwyllys 			/*
42799ebb4caSwyllys 			 * This is the case where we have had a short
42899ebb4caSwyllys 			 * but valid input line
42999ebb4caSwyllys 			 */
43099ebb4caSwyllys 			if ((v < ctx->length) && eof) {
43199ebb4caSwyllys 				rv = 0;
43299ebb4caSwyllys 				goto end;
43399ebb4caSwyllys 			} else
43499ebb4caSwyllys 				ctx->length = v;
43599ebb4caSwyllys 
43699ebb4caSwyllys 			if (seof >= 0) {
43799ebb4caSwyllys 				rv = 0;
43899ebb4caSwyllys 				goto end;
43999ebb4caSwyllys 			}
44099ebb4caSwyllys 			out += v;
44199ebb4caSwyllys 		}
44299ebb4caSwyllys 	}
44399ebb4caSwyllys 	rv = 1;
44499ebb4caSwyllys end:
44599ebb4caSwyllys 	*outl = ret;
44699ebb4caSwyllys 	ctx->num = n;
44799ebb4caSwyllys 	ctx->line_num = ln;
44899ebb4caSwyllys 	ctx->expect_nl = exp_nl;
44999ebb4caSwyllys 	return (rv);
45099ebb4caSwyllys }
45199ebb4caSwyllys 
45299ebb4caSwyllys int
PEM_DecodeFinal(PEM_ENCODE_CTX * ctx,unsigned char * out,int * outl)45399ebb4caSwyllys PEM_DecodeFinal(PEM_ENCODE_CTX *ctx, unsigned char *out, int *outl)
45499ebb4caSwyllys {
45599ebb4caSwyllys 	int i;
45699ebb4caSwyllys 
45799ebb4caSwyllys 	*outl = 0;
45899ebb4caSwyllys 	if (ctx->num != 0) {
45999ebb4caSwyllys 		i = PEM_DecodeBlock(out, ctx->enc_data, ctx->num);
46099ebb4caSwyllys 		if (i < 0)
46199ebb4caSwyllys 			return (-1);
46299ebb4caSwyllys 		ctx->num = 0;
46399ebb4caSwyllys 		*outl = i;
46499ebb4caSwyllys 		return (1);
46599ebb4caSwyllys 	} else
46699ebb4caSwyllys 		return (1);
46799ebb4caSwyllys }
46899ebb4caSwyllys 
46999ebb4caSwyllys static int
get_line(unsigned char * in,int inlen,char * buf,int buflen)470*d00756ccSwyllys get_line(unsigned char *in, int inlen, char *buf, int buflen)
47199ebb4caSwyllys {
47299ebb4caSwyllys 	int i = 0;
47399ebb4caSwyllys 
474*d00756ccSwyllys 	while ((i < inlen) && (i < buflen) && (in[i] != '\n')) {
47599ebb4caSwyllys 		buf[i] = in[i];
47699ebb4caSwyllys 		i++;
47799ebb4caSwyllys 	}
47899ebb4caSwyllys 
479*d00756ccSwyllys 	return (i);
48099ebb4caSwyllys }
48199ebb4caSwyllys 
48299ebb4caSwyllys KMF_RETURN
Pem2Der(unsigned char * in,int inlen,unsigned char ** out,int * outlen)48399ebb4caSwyllys Pem2Der(unsigned char *in, int inlen,
48499ebb4caSwyllys     unsigned char **out, int *outlen)
48599ebb4caSwyllys {
48699ebb4caSwyllys 	int kmf_rv = 0;
48799ebb4caSwyllys 	PEM_ENCODE_CTX ctx;
488fbcec901Shylee 	int i, j, k, bl = 0;
48999ebb4caSwyllys 	char buf[2048];
49073cc0e02Swyllys 	char *nameB = NULL;
49173cc0e02Swyllys 	unsigned char *dataB = NULL;
49299ebb4caSwyllys 	int total = 0;
49399ebb4caSwyllys 
49499ebb4caSwyllys 	if (in == NULL || inlen == 0 || out == NULL)
49599ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
49699ebb4caSwyllys 
49799ebb4caSwyllys 	(void) memset(buf, 0, sizeof (buf));
49899ebb4caSwyllys 
499*d00756ccSwyllys 	while (total < inlen) {
50099ebb4caSwyllys 		/*
50199ebb4caSwyllys 		 * get a line (ended at '\n'), which returns
50299ebb4caSwyllys 		 * number of bytes in the line
50399ebb4caSwyllys 		 */
504*d00756ccSwyllys 		i = get_line(in + total, inlen - total, buf, sizeof (buf));
505*d00756ccSwyllys 		if (i == 0) {
50699ebb4caSwyllys 			kmf_rv = KMF_ERR_ENCODING;
50799ebb4caSwyllys 			goto err;
50899ebb4caSwyllys 		}
50999ebb4caSwyllys 
510fbcec901Shylee 		j = i;
511fbcec901Shylee 		while ((j >= 0) && (buf[j] <= ' ')) j--;
512fbcec901Shylee 		buf[++j] = '\n';
513fbcec901Shylee 		buf[++j] = '\0';
514fbcec901Shylee 
515fbcec901Shylee 		total += i + 1;
51699ebb4caSwyllys 
51799ebb4caSwyllys 		if (strncmp(buf, "-----BEGIN ", 11) == 0) {
51899ebb4caSwyllys 			i = strlen(&(buf[11]));
51999ebb4caSwyllys 			if (strncmp(&(buf[11+i-6]), "-----\n", 6) != 0) {
52099ebb4caSwyllys 				continue;
52199ebb4caSwyllys 			}
52299ebb4caSwyllys 
52399ebb4caSwyllys 			if ((nameB = malloc(i+9)) == NULL) {
52499ebb4caSwyllys 				kmf_rv = KMF_ERR_MEMORY;
52599ebb4caSwyllys 				goto err;
52699ebb4caSwyllys 			}
52799ebb4caSwyllys 
52899ebb4caSwyllys 			(void) memcpy(nameB, &(buf[11]), i-6);
52999ebb4caSwyllys 			nameB[i-6] = '\0';
53099ebb4caSwyllys 			break;
53199ebb4caSwyllys 		}
53299ebb4caSwyllys 	}
53399ebb4caSwyllys 
53499ebb4caSwyllys 	bl = 0;
53599ebb4caSwyllys 	if ((dataB = malloc(2048)) == NULL) {
53699ebb4caSwyllys 		kmf_rv = KMF_ERR_MEMORY;
53799ebb4caSwyllys 		goto err;
53899ebb4caSwyllys 	}
53999ebb4caSwyllys 
54099ebb4caSwyllys 	dataB[0] = '\0';
54199ebb4caSwyllys 
542*d00756ccSwyllys 	while (total < inlen) {
54399ebb4caSwyllys 		(void) memset(buf, 0, 1024);
544*d00756ccSwyllys 		i = get_line(in+total, inlen - total, buf, sizeof (buf));
54599ebb4caSwyllys 
546*d00756ccSwyllys 		if (i == 0) break;
54799ebb4caSwyllys 
548fbcec901Shylee 		j = i;
549fbcec901Shylee 		while ((j >= 0) && (buf[j] <= ' '))
550fbcec901Shylee 			j--;
55199ebb4caSwyllys 
552fbcec901Shylee 		buf[++j] = '\n';
553fbcec901Shylee 		buf[++j] = '\0';
554fbcec901Shylee 		total += i + 1;
55599ebb4caSwyllys 
55699ebb4caSwyllys 		if (buf[0] == '\n') break;
557fbcec901Shylee 		if ((dataB = realloc(dataB, bl+j+9)) == NULL) {
55899ebb4caSwyllys 			kmf_rv = KMF_ERR_MEMORY;
55999ebb4caSwyllys 			goto err;
56099ebb4caSwyllys 		}
56199ebb4caSwyllys 
56299ebb4caSwyllys 		if (strncmp(buf, "-----END ", 9) == 0) {
56399ebb4caSwyllys 			break;
56499ebb4caSwyllys 		}
56599ebb4caSwyllys 
566fbcec901Shylee 		(void) memcpy(&(dataB[bl]), buf, j);
567fbcec901Shylee 		dataB[bl+j] = '\0';
568fbcec901Shylee 		bl += j;
56999ebb4caSwyllys 	}
57099ebb4caSwyllys 
571*d00756ccSwyllys 	if (nameB == NULL)
572*d00756ccSwyllys 		goto err;
573*d00756ccSwyllys 
57499ebb4caSwyllys 	i = strlen(nameB);
57599ebb4caSwyllys 	if ((strncmp(buf, "-----END ", 9) != 0) ||
57699ebb4caSwyllys 	    (strncmp(nameB, &(buf[9]), i) != 0) ||
57799ebb4caSwyllys 	    (strncmp(&(buf[9+i]), "-----", 5) != 0)) {
57899ebb4caSwyllys 		kmf_rv = KMF_ERR_ENCODING;
57999ebb4caSwyllys 		goto err;
58099ebb4caSwyllys 	}
58199ebb4caSwyllys 
58299ebb4caSwyllys 	PEM_DecodeInit(&ctx);
58399ebb4caSwyllys 	i = PEM_DecodeUpdate(&ctx,
58499ebb4caSwyllys 	    (unsigned char *)dataB, &bl, (unsigned char *)dataB, bl);
58599ebb4caSwyllys 
58699ebb4caSwyllys 	if (i < 0) {
58799ebb4caSwyllys 		kmf_rv = KMF_ERR_ENCODING;
58899ebb4caSwyllys 		goto err;
58999ebb4caSwyllys 	}
59099ebb4caSwyllys 
59199ebb4caSwyllys 	i = PEM_DecodeFinal(&ctx, (unsigned char *)&(dataB[bl]), &k);
59299ebb4caSwyllys 	if (i < 0) {
59399ebb4caSwyllys 		kmf_rv = KMF_ERR_ENCODING;
59499ebb4caSwyllys 		goto err;
59599ebb4caSwyllys 	}
59699ebb4caSwyllys 	bl += k;
59799ebb4caSwyllys 
59899ebb4caSwyllys 	if (bl == 0) goto err;
59999ebb4caSwyllys 	*out = (unsigned char *)dataB;
60099ebb4caSwyllys 	*outlen = bl;
60199ebb4caSwyllys 
60299ebb4caSwyllys err:
60373cc0e02Swyllys 	if (nameB != NULL)
60499ebb4caSwyllys 		free(nameB);
60573cc0e02Swyllys 	if (kmf_rv != KMF_OK && dataB != NULL)
60699ebb4caSwyllys 		free(dataB);
60799ebb4caSwyllys 
60899ebb4caSwyllys 	return (kmf_rv);
60999ebb4caSwyllys }
610