]> git.saurik.com Git - apple/security.git/blob - AppleX509CL/clNssUtils.cpp
Security-179.tar.gz
[apple/security.git] / AppleX509CL / clNssUtils.cpp
1 /*
2 * Copyright (c) 2003 Apple Computer, 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 obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * 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 EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18 /*
19 * clNssUtils.cpp - support for libnssasn1-based ASN1 encode/decode
20 */
21
22 #include "clNssUtils.h"
23 #include "clNameUtils.h"
24 #include "CSPAttacher.h"
25 #include <SecurityNssAsn1/secasn1.h>
26 #include <SecurityNssAsn1/SecNssCoder.h>
27 #include <SecurityNssAsn1/nssUtils.h>
28 #include <SecurityNssAsn1/keyTemplates.h>
29 #include <SecurityNssAsn1/certExtensionTemplates.h>
30 #include <Security/oidsalg.h>
31 #include <Security/cssmapple.h>
32 #include <string.h>
33
34 #pragma mark ----- ArenaAllocator -----
35
36 /*
37 * Avoid inlining this for debuggability
38 */
39 void *ArenaAllocator::malloc(size_t len) throw(std::bad_alloc)
40 {
41 try {
42 return mCoder.malloc(len);
43 }
44 catch (...) {
45 throw std::bad_alloc();
46 }
47 }
48
49 /* intentionally not implemented, should never be called */
50 void ArenaAllocator::free(void *p) throw()
51 {
52 throw std::bad_alloc();
53 }
54
55 void *ArenaAllocator::realloc(void *p, size_t len) throw(std::bad_alloc)
56 {
57 throw std::bad_alloc();
58 }
59
60 #pragma mark ----- Malloc/Copy/Compare CSSM_DATA -----
61
62 /*
63 * Misc. alloc/copy with arbitrary CssmAllocator
64 */
65 /* malloc d.Data, set d.Length */
66 void clAllocData(
67 CssmAllocator &alloc,
68 CSSM_DATA &dst,
69 size_t len)
70 {
71 if(len == 0) {
72 dst.Data = NULL;
73 }
74 else {
75 dst.Data = (uint8 *)alloc.malloc(len);
76 }
77 dst.Length = len;
78 }
79
80 /* malloc and copy */
81 void clAllocCopyData(
82 CssmAllocator &alloc,
83 const CSSM_DATA &src,
84 CSSM_DATA &dst)
85 {
86 clAllocData(alloc, dst, src.Length);
87 if(dst.Length != 0) {
88 memmove(dst.Data, src.Data, src.Length);
89 }
90 }
91
92 /*
93 * Compare two CSSM_DATAs (or two CSSM_OIDs), return true if identical.
94 */
95 bool clCompareCssmData(
96 const CSSM_DATA *data1,
97 const CSSM_DATA *data2)
98 {
99 if((data1 == NULL) || (data1->Data == NULL) ||
100 (data2 == NULL) || (data2->Data == NULL) ||
101 (data1->Length != data2->Length)) {
102 return false;
103 }
104 if(data1->Length != data2->Length) {
105 return false;
106 }
107 if(memcmp(data1->Data, data2->Data, data1->Length) == 0) {
108 return true;
109 }
110 else {
111 return false;
112 }
113 }
114
115 #pragma mark ----- CSSM_DATA <--> uint32 -----
116
117 uint32 clDataToInt(
118 const CSSM_DATA &cdata,
119 CSSM_RETURN toThrow) /* = CSSMERR_CL_INVALID_CERT_POINTER */
120 {
121 if((cdata.Length == 0) || (cdata.Data == NULL)) {
122 return 0;
123 }
124 uint32 len = cdata.Length;
125 if(len > sizeof(uint32)) {
126 CssmError::throwMe(toThrow);
127 }
128
129 uint32 rtn = 0;
130 uint8 *cp = cdata.Data;
131 for(uint32 i=0; i<len; i++) {
132 rtn = (rtn << 8) | *cp++;
133 }
134 return rtn;
135 }
136
137 void clIntToData(
138 uint32 num,
139 CSSM_DATA &cdata,
140 CssmAllocator &alloc)
141 {
142 uint32 len = 0;
143
144 if(num < 0x100) {
145 len = 1;
146 }
147 else if(num < 0x10000) {
148 len = 2;
149 }
150 else if(num < 0x1000000) {
151 len = 3;
152 }
153 else {
154 len = 4;
155 }
156 clAllocData(alloc, cdata, len);
157 uint8 *cp = &cdata.Data[len - 1];
158 for(unsigned i=0; i<len; i++) {
159 *cp-- = num & 0xff;
160 num >>= 8;
161 }
162 }
163
164 #pragma mark ----- CSSM_BOOL <--> CSSM_DATA -----
165 /*
166 * A Bool is encoded as one byte of either 0 or 0xff
167 * Default of NSS boolean not present is false
168 */
169 CSSM_BOOL clNssBoolToCssm(
170 const CSSM_DATA &nssBool)
171 {
172 if((nssBool.Data != NULL) && (nssBool.Data[0] == 0xff)) {
173 return CSSM_TRUE;
174 }
175 else {
176 return CSSM_FALSE;
177 }
178 }
179
180 void clCssmBoolToNss(
181 CSSM_BOOL cBool,
182 CSSM_DATA &nssBool,
183 CssmAllocator &alloc)
184 {
185 uint32 num = cBool ? 0xff : 0;
186 clIntToData(num, nssBool, alloc);
187 }
188
189 #pragma mark ----- Bit String manipulation -----
190
191 /*
192 * Adjust the length of a CSSM_DATA representing a pre-encoded
193 * bit string. On entry the length field is the number of bytes
194 * of data; en exit, the number if bits. Trailing zero bits
195 * are counted as unused (which is how KeyUsage and NetscapeCertType
196 * extensions are encoded).
197 */
198 void clCssmBitStringToNss(
199 CSSM_DATA &b)
200 {
201 int numBits = b.Length * 8;
202
203 /* start at end of bit array, scanning backwards looking
204 * for the first set bit */
205 bool foundSet = false;
206 for(int dex=b.Length-1; dex>=0; dex--) {
207 unsigned bitMask = 0x01;
208 uint8 byte = b.Data[dex];
209 for(unsigned bdex=0; bdex<8; bdex++) {
210 if(byte & bitMask) {
211 foundSet = true;
212 break;
213 }
214 else {
215 bitMask <<= 1;
216 numBits--;
217 }
218 }
219 if(foundSet) {
220 break;
221 }
222 }
223 /* !foundSet --> numBits = 0 */
224 assert(((numBits > 0) & foundSet) || ((numBits == 0) && !foundSet));
225 b.Length = (uint32)numBits;
226 }
227
228 /*
229 * On entry, Length is bit count; on exit, a byte count.
230 * The job here is to ensure that bits marked as "unused" in the
231 * BER encoding are cleared. Encoding rules say they are undefined in
232 * the actual encoding.
233 */
234 void clNssBitStringToCssm(
235 CSSM_DATA &b)
236 {
237 uint32 byteCount = (b.Length + 7) / 8;
238 unsigned partialBits = b.Length & 0x7;
239 b.Length = byteCount;
240 if(partialBits == 0) {
241 return;
242 }
243
244 /* mask off unused bits */
245 unsigned unusedBits = 8 - partialBits;
246 uint8 *bp = b.Data + b.Length - 1;
247 /* mask = (2 ** unusedBits) - 1 */
248 unsigned mask = (1 << unusedBits) - 1;
249 *bp &= ~mask;
250 }
251
252 #pragma mark ----- NSS array manipulation -----
253 /*
254 * How many items in a NULL-terminated array of pointers?
255 */
256 unsigned clNssArraySize(
257 const void **array)
258 {
259 unsigned count = 0;
260 if (array) {
261 while (*array++) {
262 count++;
263 }
264 }
265 return count;
266 }
267
268 /* malloc a NULL-ed array of pointers of size num+1 */
269 void **clNssNullArray(
270 uint32 num,
271 SecNssCoder &coder)
272 {
273 unsigned len = (num + 1) * sizeof(void *);
274 void **p = (void **)coder.malloc(len);
275 memset(p, 0, len);
276 return p;
277 }
278
279 /*
280 * GIven a CSSM_DATA containing a decoded BIT_STRING,
281 * convert to a KeyUsage.
282 */
283 CE_KeyUsage clBitStringToKeyUsage(
284 const CSSM_DATA &cdata)
285 {
286 unsigned toCopy = (cdata.Length + 7) / 8;
287 if(toCopy > 2) {
288 /* I hope I never see this... */
289 clErrorLog("clBitStringToKeyUsage: KeyUsage larger than 2 bytes!");
290 toCopy = 2;
291 }
292 unsigned char bits[2] = {0, 0};
293 memmove(bits, cdata.Data, toCopy);
294 CE_KeyUsage usage = (((unsigned)bits[0]) << 8) | bits[1];
295 return usage;
296 }
297
298 CSSM_ALGORITHMS CL_oidToAlg(
299 const CSSM_OID &oid)
300 {
301 CSSM_ALGORITHMS alg;
302 bool found = cssmOidToAlg(&oid, &alg);
303 if(!found) {
304 clErrorLog("CL_oidToAlg: unknown alg\n");
305 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
306 }
307 return alg;
308 }
309
310 #pragma mark ----- copy CSSM_X509_ALGORITHM_IDENTIFIER -----
311
312 /*
313 * Copy CSSM_X509_ALGORITHM_IDENTIFIER, same format (NSS and CSSM).
314 */
315 void CL_copyAlgId(
316 const CSSM_X509_ALGORITHM_IDENTIFIER &srcAlgId,
317 CSSM_X509_ALGORITHM_IDENTIFIER &dstAlgId,
318 CssmAllocator &alloc)
319 {
320 clAllocCopyData(alloc, srcAlgId.algorithm, dstAlgId.algorithm);
321 clAllocCopyData(alloc, srcAlgId.parameters, dstAlgId.parameters);
322 }
323
324 void CL_freeCssmAlgId(
325 CSSM_X509_ALGORITHM_IDENTIFIER *cdsaObj, // optional
326 CssmAllocator &alloc)
327 {
328 if(cdsaObj == NULL) {
329 return;
330 }
331 alloc.free(cdsaObj->algorithm.Data);
332 alloc.free(cdsaObj->parameters.Data);
333 memset(cdsaObj, 0, sizeof(CSSM_X509_ALGORITHM_IDENTIFIER));
334 }
335
336
337 #pragma mark ----- CSSM_X509_TIME <--> NSS format -----
338
339 /*
340 * Map the tag associated with a choice of DirectoryString elements to
341 * a template array for encoding/decoding that string type.
342 * Contrary to RFC2459, we allow the IA5String type, which is actually
343 * used in the real world (cf. the email address in Thawte's serverbasic
344 * cert).
345 */
346
347 /* The template chooser does the work here */
348
349 bool CL_nssTimeToCssm(
350 const NSS_TaggedItem &nssTime,
351 CSSM_X509_TIME &cssmObj,
352 CssmAllocator &alloc)
353 {
354 cssmObj.timeType = nssTime.tag;
355 clAllocCopyData(alloc, nssTime.item, cssmObj.time);
356 return true;
357 }
358
359 /*
360 * CSSM time to NSS time.
361 */
362 void CL_cssmTimeToNss(
363 const CSSM_X509_TIME &cssmTime,
364 NSS_TaggedItem &nssTime,
365 SecNssCoder &coder)
366 {
367 nssTime.tag = cssmTime.timeType;
368 coder.allocCopyItem(cssmTime.time, nssTime.item);
369 }
370
371 void CL_freeCssmTime(
372 CSSM_X509_TIME *cssmTime,
373 CssmAllocator &alloc)
374 {
375 if(cssmTime == NULL) {
376 return;
377 }
378 if(cssmTime->time.Data) {
379 alloc.free(cssmTime->time.Data);
380 }
381 memset(cssmTime, 0, sizeof(CSSM_X509_TIME));
382 }
383
384
385 #pragma mark ----- CSSM_X509_SUBJECT_PUBLIC_KEY_INFO <--> CSSM_KEY -----
386
387 /*
388 * Copy a CSSM_X509_SUBJECT_PUBLIC_KEY_INFO.
389 *
390 * Same format (NSS and CSSM), EXCEPT:
391 *
392 * Objects which have just been NSS decoded or are about to be
393 * NSS encoded have the subjectPublicKey.Length field in BITS
394 * since this field is wrapped in a BIT STRING upon encoding.
395 *
396 * Caller tells us which format (bits or bytes)
397 * to use for each of {src, dst}.
398 */
399 void CL_copySubjPubKeyInfo(
400 const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &srcInfo,
401 bool srcInBits,
402 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &dstInfo,
403 bool dstInBits,
404 CssmAllocator &alloc)
405 {
406 CL_copyAlgId(srcInfo.algorithm, dstInfo.algorithm, alloc);
407
408 CSSM_DATA srcKey = srcInfo.subjectPublicKey;
409 if(srcInBits) {
410 srcKey.Length = (srcKey.Length + 7) / 8;
411 }
412 clAllocCopyData(alloc, srcKey, dstInfo.subjectPublicKey);
413 if(dstInBits) {
414 dstInfo.subjectPublicKey.Length *= 8;
415 }
416 }
417
418 /*
419 * Obtain a CSSM_KEY from a CSSM_X509_SUBJECT_PUBLIC_KEY_INFO,
420 * inferring as much as we can from required fields
421 * (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO) and extensions (for
422 * KeyUse, obtained from the optional DecodedCert).
423 */
424 CSSM_KEY_PTR CL_extractCSSMKeyNSS(
425 const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &keyInfo,
426 CssmAllocator &alloc,
427 const DecodedCert *decodedCert) // optional
428 {
429 CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR) alloc.malloc(sizeof(CSSM_KEY));
430 memset(cssmKey, 0, sizeof(CSSM_KEY));
431 CSSM_KEYHEADER &hdr = cssmKey->KeyHeader;
432 CssmRemoteData keyData(alloc, cssmKey->KeyData);
433 try {
434 hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
435 /* CspId blank */
436 hdr.BlobType = CSSM_KEYBLOB_RAW;
437 hdr.AlgorithmId = CL_oidToAlg(keyInfo.algorithm.algorithm);
438 hdr.KeyAttr = CSSM_KEYATTR_MODIFIABLE | CSSM_KEYATTR_EXTRACTABLE;
439
440 /*
441 * Format inferred from AlgorithmId. I have never seen these defined
442 * anywhere, e.g., what's the format of an RSA public key in a cert?
443 * X509 certainly doesn't say. However. the following two cases are
444 * known to be correct.
445 */
446 switch(hdr.AlgorithmId) {
447 case CSSM_ALGID_RSA:
448 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
449 break;
450 case CSSM_ALGID_DSA:
451 case CSSM_ALGID_DH:
452 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_X509;
453 break;
454 case CSSM_ALGID_FEE:
455 /* CSSM_KEYBLOB_RAW_FORMAT_NONE --> DER encoded */
456 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
457 break;
458 default:
459 /* punt */
460 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
461 }
462 hdr.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
463
464 /* KeyUsage inferred from extensions */
465 if(decodedCert) {
466 hdr.KeyUsage = decodedCert->inferKeyUsage();
467 }
468 else {
469 hdr.KeyUsage = CSSM_KEYUSE_ANY;
470 }
471
472 /* start/end date unknown, leave zero */
473 hdr.WrapAlgorithmId = CSSM_ALGID_NONE;
474 hdr.WrapMode = CSSM_ALGMODE_NONE;
475
476 switch(hdr.AlgorithmId) {
477 case CSSM_ALGID_DSA:
478 case CSSM_ALGID_DH:
479 {
480 /*
481 * Just encode the whole subject public key info blob.
482 * NOTE we're assuming that the keyInfo.subjectPublicKey
483 * field is in the NSS_native BITSTRING format, i.e.,
484 * its Length field is in bits and we don't have to adjust.
485 */
486 PRErrorCode prtn = SecNssEncodeItemOdata(&keyInfo,
487 NSS_SubjectPublicKeyInfoTemplate, keyData);
488 if(prtn) {
489 clErrorLog("extractCSSMKey: error on reencode\n");
490 CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
491 }
492 break;
493 }
494 default:
495 /*
496 * RSA, FEE for now.
497 * keyInfo.subjectPublicKey (in BITS) ==> KeyData
498 */
499 keyData.copy(keyInfo.subjectPublicKey.Data,
500 (keyInfo.subjectPublicKey.Length + 7) / 8);
501 }
502 keyData.release();
503
504 /*
505 * LogicalKeySizeInBits - ask the CSP
506 */
507 CSSM_CSP_HANDLE cspHand = getGlobalCspHand(true);
508 CSSM_KEY_SIZE keySize;
509 CSSM_RETURN crtn;
510 crtn = CSSM_QueryKeySizeInBits(cspHand, CSSM_INVALID_HANDLE, cssmKey,
511 &keySize);
512 switch(crtn) {
513 default:
514 CssmError::throwMe(crtn);
515 case CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE:
516 /*
517 * This is how the CSP indicates a "partial" public key,
518 * with a valid public key value but no alg-specific
519 * parameters (currently, DSA only).
520 */
521 hdr.KeyAttr |= CSSM_KEYATTR_PARTIAL;
522 /* and drop thru */
523 case CSSM_OK:
524 cssmKey->KeyHeader.LogicalKeySizeInBits =
525 keySize.LogicalKeySizeInBits;
526 break;
527 }
528 }
529 catch (...) {
530 alloc.free(cssmKey);
531 throw;
532 }
533 return cssmKey;
534 }
535
536 /*
537 * Set up a encoded NULL for CSSM_X509_ALGORITHM_IDENTIFIER.parameters.
538 */
539 void CL_nullAlgParams(
540 CSSM_X509_ALGORITHM_IDENTIFIER &algId)
541 {
542 static const uint8 encNull[2] = { SEC_ASN1_NULL, 0 };
543 CSSM_DATA encNullData;
544 encNullData.Data = (uint8 *)encNull;
545 encNullData.Length = 2;
546
547 algId.parameters = encNullData;
548 }
549
550 /*
551 * Convert a CSSM_KEY to a CSSM_X509_SUBJECT_PUBLIC_KEY_INFO. The
552 * CSSM key must be in raw format and with a specific blob format.
553 * -- RSA keys have to be CSSM_KEYBLOB_RAW_FORMAT_PKCS1
554 * -- DSA keys have to be CSSM_KEYBLOB_RAW_FORMAT_X509
555 */
556 void CL_CSSMKeyToSubjPubKeyInfoNSS(
557 const CSSM_KEY &cssmKey,
558 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &nssKeyInfo,
559 SecNssCoder &coder)
560 {
561 const CSSM_KEYHEADER &hdr = cssmKey.KeyHeader;
562 if(hdr.BlobType != CSSM_KEYBLOB_RAW) {
563 clErrorLog("CL SetField: must specify RAW key blob\n");
564 CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT);
565 }
566 memset(&nssKeyInfo, 0, sizeof(nssKeyInfo));
567
568 /* algorithm and format dependent from here... */
569 switch(hdr.AlgorithmId) {
570 case CSSM_ALGID_RSA:
571 if(hdr.Format != CSSM_KEYBLOB_RAW_FORMAT_PKCS1) {
572 clErrorLog("CL SetField: RSA key must be in PKCS1 format\n");
573 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
574 }
575 /* and fall thru */
576 default:
577 {
578 /* Key header's algorithm --> OID */
579 const CSSM_OID *oid = cssmAlgToOid(hdr.AlgorithmId);
580 if(oid == NULL) {
581 clErrorLog("CL SetField: Unknown key algorithm\n");
582 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
583 }
584 CSSM_X509_ALGORITHM_IDENTIFIER &algId = nssKeyInfo.algorithm;
585 coder.allocCopyItem(*oid, algId.algorithm);
586
587 /* NULL algorithm parameters, always in this case */
588 CL_nullAlgParams(algId);
589
590 /* Copy key bits, destination is a BIT STRING */
591 coder.allocCopyItem(cssmKey.KeyData, nssKeyInfo.subjectPublicKey);
592 nssKeyInfo.subjectPublicKey.Length *= 8;
593 break;
594 }
595 case CSSM_ALGID_DSA:
596 if(hdr.Format != CSSM_KEYBLOB_RAW_FORMAT_X509) {
597 clErrorLog("CL SetField: DSA key must be in X509 format\n");
598 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
599 }
600
601 /*
602 * All we do is decode the whole key blob into the
603 * SubjectPublicKeyInfo.
604 */
605 if(coder.decodeItem(cssmKey.KeyData,
606 NSS_SubjectPublicKeyInfoTemplate,
607 &nssKeyInfo)) {
608 clErrorLog("CL SetField: Error decoding DSA public key\n");
609 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
610 }
611 break;
612 }
613 }
614
615 void CL_freeCSSMKey(
616 CSSM_KEY_PTR cssmKey,
617 CssmAllocator &alloc,
618 bool freeTop)
619 {
620 if(cssmKey == NULL) {
621 return;
622 }
623 alloc.free(cssmKey->KeyData.Data);
624 memset(cssmKey, 0, sizeof(CSSM_KEY));
625 if(freeTop) {
626 alloc.free(cssmKey);
627 }
628 }
629
630 #pragma mark ----- CE_AuthorityKeyID <--> NSS_AuthorityKeyId -----
631
632 void CL_cssmAuthorityKeyIdToNss(
633 const CE_AuthorityKeyID &cdsaObj,
634 NSS_AuthorityKeyId &nssObj,
635 SecNssCoder &coder)
636 {
637 memset(&nssObj, 0, sizeof(nssObj));
638 if(cdsaObj.keyIdentifierPresent) {
639 nssObj.keyIdentifier = (CSSM_DATA_PTR)coder.malloc(sizeof(CSSM_DATA));
640 coder.allocCopyItem(cdsaObj.keyIdentifier, *nssObj.keyIdentifier);
641 }
642 if(cdsaObj.generalNamesPresent ) {
643 /* GeneralNames, the hard one */
644 CL_cssmGeneralNamesToNss(*cdsaObj.generalNames,
645 nssObj.genNames, coder);
646 }
647 if(cdsaObj.serialNumberPresent) {
648 coder.allocCopyItem(cdsaObj.serialNumber,nssObj.serialNumber);
649 }
650 }
651
652 void CL_nssAuthorityKeyIdToCssm(
653 const NSS_AuthorityKeyId &nssObj,
654 CE_AuthorityKeyID &cdsaObj,
655 SecNssCoder &coder, // for temp decoding
656 CssmAllocator &alloc)
657 {
658 if(nssObj.keyIdentifier != NULL) {
659 cdsaObj.keyIdentifierPresent = CSSM_TRUE;
660 clAllocCopyData(alloc, *nssObj.keyIdentifier, cdsaObj.keyIdentifier);
661 }
662 if(nssObj.genNames.names != NULL) {
663 /* GeneralNames, the hard one */
664 cdsaObj.generalNamesPresent = CSSM_TRUE;
665 cdsaObj.generalNames =
666 (CE_GeneralNames *)alloc.malloc(sizeof(CE_GeneralNames));
667 CL_nssGeneralNamesToCssm(nssObj.genNames,
668 *cdsaObj.generalNames,
669 coder,
670 alloc);
671 }
672 if(nssObj.serialNumber.Data != NULL) {
673 cdsaObj.serialNumberPresent = CSSM_TRUE;
674 clAllocCopyData(alloc, nssObj.serialNumber, cdsaObj.serialNumber);
675 }
676 }
677
678 #pragma mark ----- decode/encode CE_DistributionPointName -----
679
680 /* This is always a DER-encoded blob at the NSS level */
681 void CL_decodeDistributionPointName(
682 const CSSM_DATA &nssBlob,
683 CE_DistributionPointName &cssmDpn,
684 SecNssCoder &coder,
685 CssmAllocator &alloc)
686 {
687 memset(&cssmDpn, 0, sizeof(CE_DistributionPointName));
688 if(nssBlob.Length == 0) {
689 clErrorLog("***CL_decodeDistributionPointName: bad PointName\n");
690 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
691 }
692 unsigned char tag = nssBlob.Data[0] & SEC_ASN1_TAGNUM_MASK;
693 switch(tag) {
694 case NSS_DIST_POINT_FULL_NAME_TAG:
695 {
696 /* decode to temp coder memory */
697 NSS_GeneralNames gnames;
698 gnames.names = NULL;
699 if(coder.decodeItem(nssBlob, NSS_DistPointFullNameTemplate,
700 &gnames)) {
701 clErrorLog("***Error decoding DistPointFullName\n");
702 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
703 }
704
705 cssmDpn.nameType = CE_CDNT_FullName;
706 cssmDpn.fullName = (CE_GeneralNames *)alloc.malloc(
707 sizeof(CE_GeneralNames));
708
709 /* copy out to caller */
710 CL_nssGeneralNamesToCssm(gnames,
711 *cssmDpn.fullName, coder, alloc);
712 break;
713 }
714 case NSS_DIST_POINT_RDN_TAG:
715 {
716 /* decode to temp coder memory */
717 NSS_RDN rdn;
718 memset(&rdn, 0, sizeof(rdn));
719 if(coder.decodeItem(nssBlob, NSS_DistPointRDNTemplate,
720 &rdn)) {
721 clErrorLog("***Error decoding DistPointRDN\n");
722 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
723 }
724
725 cssmDpn.nameType = CE_CDNT_NameRelativeToCrlIssuer;
726 cssmDpn.rdn = (CSSM_X509_RDN_PTR)alloc.malloc(
727 sizeof(CSSM_X509_RDN));
728
729 /* copy out to caller */
730 CL_nssRdnToCssm(rdn, *cssmDpn.rdn, alloc, coder);
731 break;
732 }
733 default:
734 clErrorLog("***Bad CE_DistributionPointName tag\n");
735 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
736 }
737 }
738
739 void CL_encodeDistributionPointName(
740 CE_DistributionPointName &cpoint,
741 CSSM_DATA &npoint,
742 SecNssCoder &coder)
743 {
744 const SEC_ASN1Template *templ = NULL;
745 NSS_GeneralNames gnames;
746 NSS_RDN rdn;
747 void *encodeSrc = NULL;
748
749 /*
750 * Our job is to convert one of two incoming aggregate types
751 * into NSS format, then encode the result into npoint.
752 */
753 switch(cpoint.nameType) {
754 case CE_CDNT_FullName:
755 CL_cssmGeneralNamesToNss(*cpoint.fullName,
756 gnames, coder);
757 encodeSrc = &gnames;
758 templ = NSS_DistPointFullNameTemplate;
759 break;
760
761 case CE_CDNT_NameRelativeToCrlIssuer:
762 CL_cssmRdnToNss(*cpoint.rdn, rdn, coder);
763 encodeSrc = &rdn;
764 templ = NSS_DistPointRDNTemplate;
765 break;
766 default:
767 clErrorLog("CL_encodeDistributionPointName: bad nameType\n");
768 CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
769 }
770 if(coder.encodeItem(encodeSrc, templ, npoint)) {
771 clErrorLog("CL_encodeDistributionPointName: encode error\n");
772 CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
773 }
774 }
775
776
777 #pragma mark --- CE_CRLDistPointsSyntax <--> NSS_CRLDistributionPoints ---
778
779 void CL_cssmDistPointsToNss(
780 const CE_CRLDistPointsSyntax &cdsaObj,
781 NSS_CRLDistributionPoints &nssObj,
782 SecNssCoder &coder)
783 {
784 memset(&nssObj, 0, sizeof(nssObj));
785 unsigned numPoints = cdsaObj.numDistPoints;
786 if(numPoints == 0) {
787 return;
788 }
789 nssObj.distPoints =
790 (NSS_DistributionPoint **)clNssNullArray(numPoints, coder);
791 for(unsigned dex=0; dex<numPoints; dex++) {
792 nssObj.distPoints[dex] = (NSS_DistributionPoint *)
793 coder.malloc(sizeof(NSS_DistributionPoint));
794 NSS_DistributionPoint *npoint = nssObj.distPoints[dex];
795 memset(npoint, 0, sizeof(NSS_DistributionPoint));
796 CE_CRLDistributionPoint *cpoint = &cdsaObj.distPoints[dex];
797
798 /* all fields are optional */
799 if(cpoint->distPointName) {
800 /* encode and drop into ASN_ANY slot */
801 npoint->distPointName = (CSSM_DATA *)
802 coder.malloc(sizeof(CSSM_DATA));
803 CL_encodeDistributionPointName(*cpoint->distPointName,
804 *npoint->distPointName, coder);
805
806 }
807
808 if(cpoint->reasonsPresent) {
809 /* bit string, presumed max length 8 bits */
810 coder.allocItem(npoint->reasons, 1);
811 npoint->reasons.Data[0] = cpoint->reasons;
812 /* adjust for bit string length */
813 npoint->reasons.Length = 8;
814 }
815
816 if(cpoint->crlIssuer) {
817 CL_cssmGeneralNamesToNss(*cpoint->crlIssuer,
818 npoint->crlIssuer, coder);
819 }
820 }
821 }
822
823 void CL_nssDistPointsToCssm(
824 const NSS_CRLDistributionPoints &nssObj,
825 CE_CRLDistPointsSyntax &cdsaObj,
826 SecNssCoder &coder, // for temp decoding
827 CssmAllocator &alloc)
828 {
829 memset(&cdsaObj, 0, sizeof(cdsaObj));
830 unsigned numPoints = clNssArraySize((const void **)nssObj.distPoints);
831 if(numPoints == 0) {
832 return;
833 }
834
835 unsigned len = sizeof(CE_CRLDistributionPoint) * numPoints;
836 cdsaObj.distPoints = (CE_CRLDistributionPoint *)alloc.malloc(len);
837 memset(cdsaObj.distPoints, 0, len);
838 cdsaObj.numDistPoints = numPoints;
839
840 for(unsigned dex=0; dex<numPoints; dex++) {
841 CE_CRLDistributionPoint &cpoint = cdsaObj.distPoints[dex];
842 NSS_DistributionPoint &npoint = *(nssObj.distPoints[dex]);
843
844 /* All three fields are optional */
845 if(npoint.distPointName != NULL) {
846 /* Drop in a CE_DistributionPointName */
847 CE_DistributionPointName *cname =
848 (CE_DistributionPointName *)alloc.malloc(
849 sizeof(CE_DistributionPointName));
850 memset(cname, 0, sizeof(*cname));
851 cpoint.distPointName = cname;
852
853 /*
854 * This one is currently still encoded; we have to peek
855 * at its tag and decode accordingly.
856 */
857 CL_decodeDistributionPointName(*npoint.distPointName,
858 *cname, coder, alloc);
859 }
860
861 if(npoint.reasons.Data != NULL) {
862 /* careful, it's a bit string */
863 if(npoint.reasons.Length > 8) {
864 clErrorLog("***CL_nssDistPointsToCssm: Malformed reasons\n");
865 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
866 }
867 cpoint.reasonsPresent = CSSM_TRUE;
868 if(npoint.reasons.Length != 0) {
869 cpoint.reasons = npoint.reasons.Data[0];
870 }
871 }
872
873 if(npoint.crlIssuer.names != NULL) {
874 /* Cook up a new CE_GeneralNames */
875 cpoint.crlIssuer =
876 (CE_GeneralNames *)alloc.malloc(sizeof(CE_GeneralNames));
877 CL_nssGeneralNamesToCssm(npoint.crlIssuer, *cpoint.crlIssuer,
878 coder, alloc);
879 }
880 }
881 }
882
883 #pragma mark ----- IssuingDistributionPoint -----
884
885 void CL_nssIssuingDistPointToCssm(
886 NSS_IssuingDistributionPoint *nssIdp,
887 CE_IssuingDistributionPoint *cssmIdp,
888 SecNssCoder &coder,
889 CssmAllocator &alloc)
890 {
891 /* All fields optional */
892 memset(cssmIdp, 0, sizeof(*cssmIdp));
893 if(nssIdp->distPointName) {
894 CE_DistributionPointName *cssmDp = (CE_DistributionPointName *)
895 alloc.malloc(sizeof(CE_DistributionPointName));
896
897 /*
898 * This one is currently still encoded; we have to peek
899 * at its tag and decode accordingly.
900 */
901 CL_decodeDistributionPointName(*nssIdp->distPointName,
902 *cssmDp, coder, alloc);
903 cssmIdp->distPointName = cssmDp;
904 }
905 if(nssIdp->onlyUserCerts) {
906 cssmIdp->onlyUserCertsPresent = CSSM_TRUE;
907 cssmIdp->onlyUserCerts = clNssBoolToCssm(*nssIdp->onlyUserCerts);
908 }
909 if(nssIdp->onlyCACerts) {
910 cssmIdp->onlyCACertsPresent = CSSM_TRUE;
911 cssmIdp->onlyCACerts = clNssBoolToCssm(*nssIdp->onlyCACerts);
912 }
913 if(nssIdp->onlySomeReasons) {
914 cssmIdp->onlySomeReasonsPresent = CSSM_TRUE;
915 if(nssIdp->onlySomeReasons->Length > 0) {
916 cssmIdp->onlySomeReasons = *nssIdp->onlySomeReasons->Data;
917 }
918 else {
919 cssmIdp->onlySomeReasons = 0;
920 }
921 }
922 if(nssIdp->indirectCRL) {
923 cssmIdp->indirectCrlPresent = CSSM_TRUE;
924 cssmIdp->indirectCrl = clNssBoolToCssm(*nssIdp->indirectCRL);
925 }
926 }
927
928 #pragma mark ----- Top-level Cert/CRL encode and decode -----
929
930 /*
931 * To ensure a secure means of signing and verifying TBSCert blobs, we
932 * provide these functions to encode and decode just the top-level
933 * elements of a certificate. Unfortunately there is no guarantee
934 * that when you decode and re-encode a TBSCert blob, you get the
935 * same thing you started with (although with DER rules, as opposed
936 * to BER rules, you should). Thus when signing, we sign the TBSCert
937 * and encode the signed cert here without ever decoding the TBSCert (or,
938 * at least, without using the decoded version to get the encoded TBS blob).
939 */
940
941 void CL_certCrlDecodeComponents(
942 const CssmData &signedItem, // DER-encoded cert or CRL
943 CssmOwnedData &tbsBlob, // still DER-encoded
944 CssmOwnedData &algId, // ditto
945 CssmOwnedData &rawSig) // raw bits (not an encoded AsnBits)
946 {
947 /* BER-decode into temp memory */
948 NSS_SignedCertOrCRL nssObj;
949 SecNssCoder coder;
950 PRErrorCode prtn;
951
952 memset(&nssObj, 0, sizeof(nssObj));
953 prtn = coder.decode(signedItem.data(), signedItem.length(),
954 NSS_SignedCertOrCRLTemplate, &nssObj);
955 if(prtn) {
956 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
957 }
958
959 /* tbsBlob and algId are raw ASN_ANY including tags, which we pass
960 * back to caller intact */
961 tbsBlob.copy(nssObj.tbsBlob.Data, nssObj.tbsBlob.Length);
962 algId.copy(nssObj.signatureAlgorithm.Data,
963 nssObj.signatureAlgorithm.Length);
964
965 /* signature is a bit string which we do in fact decode */
966 rawSig.copy(nssObj.signature.Data,
967 (nssObj.signature.Length + 7) / 8);
968 }
969
970
971 /*
972 * Given pre-DER-encoded blobs, do the final encode step for a signed cert.
973 */
974 void
975 CL_certEncodeComponents(
976 const CssmData &TBSCert, // DER-encoded
977 const CssmData &algId, // ditto
978 const CssmData &rawSig, // raw bits, not encoded
979 CssmOwnedData &signedCert) // DER-encoded
980 {
981 NSS_SignedCertOrCRL nssObj;
982 nssObj.tbsBlob.Data = TBSCert.Data;
983 nssObj.tbsBlob.Length = TBSCert.Length;
984 nssObj.signatureAlgorithm.Data = algId.Data;
985 nssObj.signatureAlgorithm.Length = algId.Length;
986 nssObj.signature.Data = rawSig.Data;
987 nssObj.signature.Length = rawSig.Length * 8; // BIT STRING
988
989 PRErrorCode prtn;
990
991 prtn = SecNssEncodeItemOdata(&nssObj,
992 NSS_SignedCertOrCRLTemplate,signedCert);
993 if(prtn) {
994 CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
995 }
996
997 }