]> git.saurik.com Git - apple/security.git/blame - CertTool/cdsaUtils/cuEnc64.c
Security-54.1.9.tar.gz
[apple/security.git] / CertTool / cdsaUtils / cuEnc64.c
CommitLineData
29654253
A
1/* Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
2 *
3 * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT
4 * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE
5 * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE COMPUTER, INC. AND THE
6 * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE COMPUTER,
7 * INC. ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL
8 * EXPOSE YOU TO LIABILITY.
9 ***************************************************************************
10 *
11 * enc64.c - encode/decode in 64-char IA5 format, per RFC 1421
12 *
13 * Revision History
14 * ----------------
15 * 11/27/98 dmitch
16 * Added ECDSA_VERIFY_ONLY dependencies.
17 * 10/06/98 ap
18 * Changed to compile with C++.
19 * 12 Dec 96 Doug Mitchell at NeXT
20 * Newlines optional in dec64() and isValidEnc64().
21 * 9 Oct 96 Doug Mitchell at NeXT
22 * Created.
23 */
24
25#include "cuEnc64.h"
26#include <stdlib.h>
27
28/*
29 * 11/27/98 dmitch: The ECDSA_VERIFY_ONLY symbol, when #defined, disables all
30 * of the code in this module except that which is necessary for ECDSA
31 * siggnature verification.
32 */
33
34#ifndef NULL
35#define NULL ((void *)0)
36#endif /* NULL */
37
38/*
39 * map a 6-bit binary value to a printable character.
40 */
41static const
42unsigned char bintoasc[] =
43 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
44
45/*
46 * Map an 7-bit printable character to its corresponding binary value.
47 * Any illegal characters return high bit set.
48 */
49static const
50unsigned char asctobin[] =
51{
52 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
53 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
54 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
55 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
56 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
57 0x80, 0x80, 0x80, 0x3e, 0x80, 0x80, 0x80, 0x3f,
58 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
59 0x3c, 0x3d, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
60 0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
61 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
62 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
63 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x80,
64 0x80, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
65 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
66 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
67 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80
68};
69
70/*
71 * map 6 bits to a printing char
72 */
73#define ENC(c) (bintoasc[((c) & 0x3f)])
74
75#define PAD '='
76
77/*
78 * map one group of up to 3 bytes at inp to 4 bytes at outp.
79 * Count is number of valid bytes in *inp; if less than 3, the
80 * 1 or two extras must be zeros.
81 */
82static void encChunk(const unsigned char *inp,
83 unsigned char *outp,
84 int count)
85{
86 unsigned char c1, c2, c3, c4;
87
88 c1 = *inp >> 2;
89 c2 = ((inp[0] << 4) & 0x30) | ((inp[1] >> 4) & 0xf);
90 c3 = ((inp[1] << 2) & 0x3c) | ((inp[2] >> 6) & 0x3);
91 c4 = inp[2] & 0x3f;
92 *outp++ = ENC(c1);
93 *outp++ = ENC(c2);
94 if (count == 1) {
95 *outp++ = PAD;
96 *outp = PAD;
97 } else {
98 *outp++ = ENC(c3);
99 if (count == 2) {
100 *outp = PAD;
101 }
102 else {
103 *outp = ENC(c4);
104 }
105 }
106}
107
108/*
109 * Given input buffer inbuf, length inlen, encode to 64-char IA5 format.
110 * Result is fmalloc'd and returned; it is terminated by Microsoft-style
111 * newline and NULL. Its length (including the trailing newline and NULL)
112 * is returned in *outlen.
113 */
114
115unsigned char *enc64(const unsigned char *inbuf,
116 unsigned inlen,
117 unsigned *outlen) // RETURNED
118{
119 return enc64WithLines(inbuf, inlen, 0, outlen);
120}
121
122unsigned char *enc64WithLines(const unsigned char *inbuf,
123 unsigned inlen,
124 unsigned linelen,
125 unsigned *outlen)
126{
127 unsigned outTextLen;
128 unsigned len; // to malloc, liberal
129 unsigned olen = 0; // actual output size
130 unsigned char *outbuf;
131 unsigned char endbuf[3];
132 int i;
133 unsigned char *outp;
134 unsigned numLines;
135 unsigned thisLine;
136
137 outTextLen = ((inlen + 2) / 3) * 4;
138 if(linelen) {
139 /*
140 * linelen must be 0 mod 4 for this to work; round up...
141 */
142 if((linelen & 0x03) != 0) {
143 linelen = (linelen + 3) & 0xfffffffc;
144 }
145 numLines = (outTextLen + linelen - 1)/ linelen;
146 }
147 else {
148 numLines = 1;
149 }
150
151 /*
152 * Total output size = encoded text size plus one newline per
153 * line of output, plus trailing NULL. We always generate newlines
154 * as \n; when decoding, we tolerate \r\n (Microsoft) or \n.
155 */
156 len = outTextLen + (2 * numLines) + 1;
157 outbuf = (unsigned char*)malloc(len);
158 outp = outbuf;
159 thisLine = 0;
160
161 while(inlen) {
162 if(inlen < 3) {
163 for(i=0; i<3; i++) {
164 if(i < inlen) {
165 endbuf[i] = inbuf[i];
166 }
167 else {
168 endbuf[i] = 0;
169 }
170 }
171 encChunk(endbuf, outp, inlen);
172 inlen = 0;
173 }
174 else {
175 encChunk(inbuf, outp, 3);
176 inlen -= 3;
177 inbuf += 3;
178 }
179 outp += 4;
180 thisLine += 4;
181 olen += 4;
182 if((linelen != 0) && (thisLine >= linelen) && inlen) {
183 /*
184 * last trailing newline added below
185 * Note we don't split 4-byte output chunks over newlines
186 */
187 *outp++ = '\n';
188 olen++;
189 thisLine = 0;
190 }
191 }
192 *outp++ = '\n';
193 *outp = '\0';
194 olen += 2;
195 *outlen = olen;
196 return outbuf;
197}
198
199static inline int isWhite(unsigned char c)
200{
201 switch(c) {
202 case '\n':
203 case '\r':
204 case ' ':
205 case '\t':
206 case '\0':
207 return 1;
208 default:
209 return 0;
210 }
211}
212
213/*
214 * Strip off all whitespace from a (supposedly) enc64-format string.
215 * Returns a malloc'd string.
216 */
217static unsigned char *stringCleanse(const unsigned char *inbuf,
218 unsigned inlen,
219 unsigned *outlen)
220{
221 unsigned char *news; // cleansed inbuf
222 unsigned newsDex; // index into news
223 unsigned i;
224
225 news = (unsigned char*)malloc(inlen);
226 newsDex = 0;
227 for(i=0; i<inlen; i++) {
228 if(!isWhite(inbuf[i])) {
229 news[newsDex++] = inbuf[i];
230 }
231 }
232 *outlen = newsDex;
233 return news;
234}
235
236/*
237 * Given input buffer inbuf, length inlen, decode from 64-char IA5 format to
238 * binary. Result is malloced and returned; its length is returned in *outlen.
239 * NULL return indicates corrupted input.
240 *
241 * All whitespace in input is ignored.
242 */
243unsigned char *dec64(const unsigned char *inbuf,
244 unsigned inlen,
245 unsigned *outlen)
246{
247 unsigned char *outbuf;
248 unsigned char *outp; // malloc'd outbuf size
249 unsigned obuflen;
250 const unsigned char *bp;
251 unsigned olen = 0; // actual output size
252 unsigned char c1, c2, c3, c4;
253 unsigned char j;
254 unsigned thisOlen;
255 unsigned char *news; // cleansed inbuf
256 unsigned newsLen;
257
258 /*
259 * Strip out all whitespace; remainder must be multiple of four
260 * characters
261 */
262 news = stringCleanse(inbuf, inlen, &newsLen);
263 if((newsLen & 0x03) != 0) {
264 free(news);
265 return (unsigned char*) NULL;
266 }
267 inlen = newsLen;
268 bp = news;
269
270 obuflen = (inlen / 4) * 3;
271 outbuf = (unsigned char*)malloc(obuflen);
272 outp = outbuf;
273
274 while (inlen) {
275 /*
276 * Note inlen is always a multiple of four here
277 */
278 if (*bp & 0x80 || (c1 = asctobin[*bp]) & 0x80) {
279 goto errorOut;
280 }
281 inlen--;
282 bp++;
283 if (*bp & 0x80 || (c2 = asctobin[*bp]) & 0x80){
284 goto errorOut;
285 }
286 inlen--;
287 bp++;
288 if (*bp == PAD) {
289 /*
290 * two input bytes, one output byte
291 */
292 c3 = c4 = 0;
293 thisOlen = 1;
294 if (c2 & 0xf) {
295 goto errorOut;
296 }
297 bp++;
298 inlen--;
299 if (*bp == PAD) {
300 bp++;
301 inlen--;
302 if(inlen > 0) {
303 goto errorOut;
304 }
305 }
306 else {
307 goto errorOut;
308 }
309 } else if (*bp & 0x80 || (c3 = asctobin[*bp]) & 0x80) {
310 goto errorOut;
311 } else {
312 bp++;
313 inlen--;
314 if (*bp == PAD) {
315 /*
316 * Three input bytes, two output
317 */
318 c4 = 0;
319 thisOlen = 2;
320 if (c3 & 3) {
321 goto errorOut;
322 }
323 } else if (*bp & 0x80 || (c4 = asctobin[*bp]) & 0x80) {
324 goto errorOut;
325 } else {
326 /*
327 * Normal non-pad case
328 */
329 thisOlen = 3;
330 }
331 bp++;
332 inlen--;
333 }
334 j = (c1 << 2) | (c2 >> 4);
335 *outp++ = j;
336 if(thisOlen > 1) {
337 j = (c2 << 4) | (c3 >> 2);
338 *outp++ = j;
339 if(thisOlen == 3) {
340 j = (c3 << 6) | c4;
341 *outp++ = j;
342 }
343 }
344 olen += thisOlen;
345 }
346 free(news);
347 *outlen = olen;
348 return outbuf; /* normal return */
349
350errorOut:
351 free(news);
352 free(outbuf);
353 return (unsigned char*) NULL;
354}
355
356/*
357 * Determine if specified input data is valid enc64 format. Returns 1
358 * if valid, 0 if not.
359 * This doesn't do a full enc64 parse job; it scans for legal characters
360 * and proper sync when a possible pad is found.
361 */
362int isValidEnc64(const unsigned char *inbuf,
363 unsigned inlen)
364{
365 int padChars = 0; // running count of PAD chars
366 int validEncChars = 0;
367 unsigned char c;
368
369 /*
370 * -- scan inbuf
371 * -- skip whitespace
372 * -- count valid chars
373 * -- ensure not more than 2 PAD chars, only at end
374 * -- ensure valid chars mod 4 == 0
375 */
376
377 while(inlen) {
378 c = *inbuf++;
379 inlen--;
380 if(isWhite(c)) {
381 continue;
382 }
383 if(c == PAD) {
384 if(++padChars > 2) {
385 return 0; // max of 2 PAD chars at end
386 }
387 }
388 else if(padChars > 0) {
389 return 0; // no normal chars after seeing PAD
390 }
391 else if((c & 0x80) || ((asctobin[c]) & 0x80)) {
392 return 0; // invalid encoded char
393 }
394 validEncChars++;
395 }
396 if((validEncChars & 0x03) != 0) {
397 return 0;
398 }
399 else {
400 return 1;
401 }
402}