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