]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cdsa_utils/lib/cuPem.cpp
Security-57740.31.2.tar.gz
[apple/security.git] / OSX / libsecurity_cdsa_utils / lib / cuPem.cpp
1 /*
2 * Copyright (c) 2003,2011-2012,2014 Apple Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please
7 * obtain a copy of the License at http://www.apple.com/publicsource and
8 * read it before using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
12 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
13 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
15 * Please see the License for the specific language governing rights and
16 * limitations under the License.
17 */
18
19 /*
20 File: cuPem.h
21
22 Description: PEM encode/decode routines
23
24 Author: dmitch
25
26 */
27
28 #include "cuPem.h"
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <strings.h>
32 #include <ctype.h>
33 #include "cuEnc64.h"
34
35 #define PEM_SCAN_LEN 8192
36
37 /*
38 * Determine if specified blob appears to be PEM format.
39 * Returns 1 if so, 0 if not.
40 */
41 int isPem(
42 const unsigned char *inData,
43 unsigned inDataLen)
44 {
45 /*
46 * 1. The entire blob must be printable ASCII.
47 */
48 const unsigned char *cp = inData;
49 for(unsigned dex=0; dex<inDataLen; dex++, cp++) {
50 if(!isprint(*cp) && !isspace(*cp)) {
51 return 0;
52 }
53 }
54
55 /*
56 * Search for "-----BEGIN " and "-----END".
57 * No strnstr() on X, so copy and NULL terminate to use strstr.
58 * First, get the first PEM_SCAN_LEN chars or inDataLen, whichever
59 * is less.
60 */
61 unsigned char buf[PEM_SCAN_LEN + 1];
62 unsigned len = inDataLen;
63 if(len > PEM_SCAN_LEN) {
64 len = PEM_SCAN_LEN;
65 }
66 memcpy(buf, inData, len);
67 buf[len] = '\0';
68 const char *p = strstr((const char *)buf, "-----BEGIN ");
69 if(p == NULL) {
70 return 0;
71 }
72
73 /*
74 * Now the last PEM_SCAN_LEN chars or inDataLen, whichever is less.
75 */
76 if(inDataLen > PEM_SCAN_LEN) {
77 memcpy(buf, inData + inDataLen - PEM_SCAN_LEN, PEM_SCAN_LEN);
78 buf[PEM_SCAN_LEN] = '\0';
79 }
80 /* else we already have whole blob in buf[] */
81 p = strstr((const char *)buf, "-----END ");
82 if(p == NULL) {
83 return 0;
84 }
85 /* success */
86 return 1;
87 }
88
89 int pemEncode(
90 const unsigned char *inData,
91 unsigned inDataLen,
92 unsigned char **outData,
93 unsigned *outDataLen,
94 const char *headerString)
95 {
96 unsigned char *enc;
97 unsigned encLen;
98
99 /* First base64 encode */
100 enc = cuEnc64WithLines(inData, inDataLen, 64, &encLen);
101 if(enc == NULL) {
102 /* malloc error is actually the only known failure */
103 printf("***pemEncode: Error encoding file. Aborting.\n");
104 return -1;
105 }
106
107 /* estimate outsize - just be sloppy, way conservative */
108 size_t outSize = encLen + (2 * strlen(headerString)) + 200;
109 *outData = (unsigned char *)malloc(outSize);
110 sprintf((char *)*outData, "-----BEGIN %s-----\n%s-----END %s-----\n",
111 headerString, (char *)enc, headerString);
112 *outDataLen = (unsigned int)strlen((char *)*outData);
113
114 if((*outData)[*outDataLen - 1] == '\0') {
115 (*outDataLen)--;
116 }
117 free(enc);
118 return 0;
119 }
120
121 int pemDecode(
122 const unsigned char *inData,
123 unsigned inDataLen,
124 unsigned char **outData,
125 unsigned *outDataLen)
126 {
127 char *cp;
128 char *curr1, *curr2;
129 char *startPem = NULL;
130 char *endPem = NULL;
131 unsigned char *out;
132 unsigned outLen;
133 int ourRtn = 0;
134 char *freeCp = NULL;
135
136 /* make the whole thing a NULL-terminated string */
137 if(inData[inDataLen - 1] != '\0') {
138 cp = freeCp = (char *)malloc(inDataLen + 1);
139 memmove(cp, inData, inDataLen);
140 cp[inDataLen] = '\0';
141 inDataLen++;
142 }
143 else {
144 /* already is */
145 cp = (char *)inData;
146 }
147
148 /* cp is start of NULL-terminated buffer, size inDataLen */
149 /* skip over everything until "-----" */
150 curr1 = strstr(cp, "-----");
151 if(curr1 == NULL) {
152 printf("***pemDecode: no terminator found\n");
153 ourRtn = -1;
154 goto abort;
155 }
156
157 /* find end of separator line, handling both flavors of terminator */
158 cp = curr1;
159 curr1 = strchr(cp, '\n');
160 curr2 = strchr(cp, '\r');
161 if((curr1 == NULL) & (curr2 == NULL)) {
162 printf("***pemDecode: Bad PEM format (1)\n");
163 ourRtn = -1;
164 goto abort;
165 }
166 if(curr1 == NULL) {
167 startPem = curr2;
168 }
169 else {
170 startPem = curr1;
171 }
172
173 /* startPem points to end of separator line */
174 /* locate ending terminator and lop it off */
175 curr1 = strstr(startPem, "-----");
176 if(curr1 == NULL) {
177 printf("***pemDecode: Bad PEM format (2)\n");
178 ourRtn = -1;
179 goto abort;
180 }
181 endPem = curr1;
182 /* endPem points to last PEM data plus one */
183
184 out = cuDec64((unsigned char *)startPem, (unsigned int)(endPem-startPem), &outLen);
185 if(out == NULL) {
186 printf("Bad PEM format (3)\n");
187 ourRtn = -1;
188 goto abort;
189 }
190 *outData = out;
191 *outDataLen = outLen;
192 abort:
193 if(freeCp) {
194 free(freeCp);
195 }
196 return ourRtn;
197 }
198