]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
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 <security_asn1/secasn1.h> | |
26 | #include <security_asn1/SecNssCoder.h> | |
27 | #include <security_asn1/nssUtils.h> | |
28 | #include <Security/keyTemplates.h> | |
29 | #include <Security/certExtensionTemplates.h> | |
30 | #include <Security/oidsalg.h> | |
31 | #include <Security/oidsattr.h> | |
32 | #include <Security/cssmapple.h> | |
33 | #include <string.h> | |
34 | ||
35 | #pragma mark ----- ArenaAllocator ----- | |
36 | ||
37 | /* | |
38 | * Avoid inlining this for debuggability | |
39 | */ | |
40 | void *ArenaAllocator::malloc(size_t len) throw(std::bad_alloc) | |
41 | { | |
42 | try { | |
43 | return mCoder.malloc(len); | |
44 | } | |
45 | catch (...) { | |
46 | throw std::bad_alloc(); | |
47 | } | |
48 | } | |
49 | ||
50 | /* intentionally not implemented, should never be called */ | |
51 | void ArenaAllocator::free(void *p) throw() | |
52 | { | |
53 | throw std::bad_alloc(); | |
54 | } | |
55 | ||
56 | void *ArenaAllocator::realloc(void *p, size_t len) throw(std::bad_alloc) | |
57 | { | |
58 | throw std::bad_alloc(); | |
59 | } | |
60 | ||
61 | #pragma mark ----- Malloc/Copy/Compare CSSM_DATA ----- | |
62 | ||
63 | /* | |
64 | * Misc. alloc/copy with arbitrary Allocator | |
65 | */ | |
66 | /* malloc d.Data, set d.Length */ | |
67 | void clAllocData( | |
68 | Allocator &alloc, | |
69 | CSSM_DATA &dst, | |
70 | size_t len) | |
71 | { | |
72 | if(len == 0) { | |
73 | dst.Data = NULL; | |
74 | } | |
75 | else { | |
76 | dst.Data = (uint8 *)alloc.malloc(len); | |
77 | } | |
78 | dst.Length = len; | |
79 | } | |
80 | ||
81 | /* malloc and copy */ | |
82 | void clAllocCopyData( | |
83 | Allocator &alloc, | |
84 | const CSSM_DATA &src, | |
85 | CSSM_DATA &dst) | |
86 | { | |
87 | clAllocData(alloc, dst, src.Length); | |
88 | if(dst.Length != 0) { | |
89 | memmove(dst.Data, src.Data, src.Length); | |
90 | } | |
91 | } | |
92 | ||
93 | /* | |
94 | * Compare two CSSM_DATAs (or two CSSM_OIDs), return true if identical. | |
95 | */ | |
96 | bool clCompareCssmData( | |
97 | const CSSM_DATA *data1, | |
98 | const CSSM_DATA *data2) | |
99 | { | |
100 | if((data1 == NULL) || (data1->Data == NULL) || | |
101 | (data2 == NULL) || (data2->Data == NULL) || | |
102 | (data1->Length != data2->Length)) { | |
103 | return false; | |
104 | } | |
105 | if(data1->Length != data2->Length) { | |
106 | return false; | |
107 | } | |
108 | if(memcmp(data1->Data, data2->Data, data1->Length) == 0) { | |
109 | return true; | |
110 | } | |
111 | else { | |
112 | return false; | |
113 | } | |
114 | } | |
115 | ||
116 | #pragma mark ----- CSSM_DATA <--> uint32 ----- | |
117 | ||
118 | uint32 clDataToInt( | |
119 | const CSSM_DATA &cdata, | |
120 | CSSM_RETURN toThrow) /* = CSSMERR_CL_INVALID_CERT_POINTER */ | |
121 | { | |
122 | if((cdata.Length == 0) || (cdata.Data == NULL)) { | |
123 | return 0; | |
124 | } | |
125 | uint32 len = cdata.Length; | |
126 | if(len > sizeof(uint32)) { | |
127 | if(toThrow == 0) { | |
128 | /* tolerate this */ | |
129 | len = sizeof(uint32); | |
130 | } | |
131 | else { | |
132 | CssmError::throwMe(toThrow); | |
133 | } | |
134 | } | |
135 | ||
136 | uint32 rtn = 0; | |
137 | uint8 *cp = cdata.Data; | |
138 | for(uint32 i=0; i<len; i++) { | |
139 | rtn = (rtn << 8) | *cp++; | |
140 | } | |
141 | return rtn; | |
142 | } | |
143 | ||
144 | void clIntToData( | |
145 | uint32 num, | |
146 | CSSM_DATA &cdata, | |
147 | Allocator &alloc) | |
148 | { | |
149 | uint32 len = 0; | |
150 | ||
151 | if(num < 0x100) { | |
152 | len = 1; | |
153 | } | |
154 | else if(num < 0x10000) { | |
155 | len = 2; | |
156 | } | |
157 | else if(num < 0x1000000) { | |
158 | len = 3; | |
159 | } | |
160 | else { | |
161 | len = 4; | |
162 | } | |
163 | clAllocData(alloc, cdata, len); | |
164 | uint8 *cp = &cdata.Data[len - 1]; | |
165 | for(unsigned i=0; i<len; i++) { | |
166 | *cp-- = num & 0xff; | |
167 | num >>= 8; | |
168 | } | |
169 | } | |
170 | ||
171 | #pragma mark ----- CSSM_BOOL <--> CSSM_DATA ----- | |
172 | /* | |
173 | * A Bool is encoded as one byte of either 0 or 0xff | |
174 | * Default of NSS boolean not present is false | |
175 | */ | |
176 | CSSM_BOOL clNssBoolToCssm( | |
177 | const CSSM_DATA &nssBool) | |
178 | { | |
179 | if((nssBool.Data != NULL) && (nssBool.Data[0] == 0xff)) { | |
180 | return CSSM_TRUE; | |
181 | } | |
182 | else { | |
183 | return CSSM_FALSE; | |
184 | } | |
185 | } | |
186 | ||
187 | void clCssmBoolToNss( | |
188 | CSSM_BOOL cBool, | |
189 | CSSM_DATA &nssBool, | |
190 | Allocator &alloc) | |
191 | { | |
192 | uint32 num = cBool ? 0xff : 0; | |
193 | clIntToData(num, nssBool, alloc); | |
194 | } | |
195 | ||
196 | #pragma mark ----- Bit String manipulation ----- | |
197 | ||
198 | /* | |
199 | * Adjust the length of a CSSM_DATA representing a pre-encoded | |
200 | * bit string. On entry the length field is the number of bytes | |
201 | * of data; en exit, the number if bits. Trailing zero bits | |
202 | * are counted as unused (which is how KeyUsage and NetscapeCertType | |
203 | * extensions are encoded). | |
204 | */ | |
205 | void clCssmBitStringToNss( | |
206 | CSSM_DATA &b) | |
207 | { | |
208 | int numBits = b.Length * 8; | |
209 | ||
210 | /* start at end of bit array, scanning backwards looking | |
211 | * for the first set bit */ | |
212 | bool foundSet = false; | |
213 | for(int dex=b.Length-1; dex>=0; dex--) { | |
214 | unsigned bitMask = 0x01; | |
215 | uint8 byte = b.Data[dex]; | |
216 | for(unsigned bdex=0; bdex<8; bdex++) { | |
217 | if(byte & bitMask) { | |
218 | foundSet = true; | |
219 | break; | |
220 | } | |
221 | else { | |
222 | bitMask <<= 1; | |
223 | numBits--; | |
224 | } | |
225 | } | |
226 | if(foundSet) { | |
227 | break; | |
228 | } | |
229 | } | |
230 | /* !foundSet --> numBits = 0 */ | |
231 | assert(((numBits > 0) & foundSet) || ((numBits == 0) && !foundSet)); | |
232 | b.Length = (uint32)numBits; | |
233 | } | |
234 | ||
235 | /* | |
236 | * On entry, Length is bit count; on exit, a byte count. | |
237 | * The job here is to ensure that bits marked as "unused" in the | |
238 | * BER encoding are cleared. Encoding rules say they are undefined in | |
239 | * the actual encoding. | |
240 | */ | |
241 | void clNssBitStringToCssm( | |
242 | CSSM_DATA &b) | |
243 | { | |
244 | uint32 byteCount = (b.Length + 7) / 8; | |
245 | unsigned partialBits = b.Length & 0x7; | |
246 | b.Length = byteCount; | |
247 | if(partialBits == 0) { | |
248 | return; | |
249 | } | |
250 | ||
251 | /* mask off unused bits */ | |
252 | unsigned unusedBits = 8 - partialBits; | |
253 | uint8 *bp = b.Data + b.Length - 1; | |
254 | /* mask = (2 ** unusedBits) - 1 */ | |
255 | unsigned mask = (1 << unusedBits) - 1; | |
256 | *bp &= ~mask; | |
257 | } | |
258 | ||
259 | #pragma mark ----- NSS array manipulation ----- | |
260 | /* | |
261 | * How many items in a NULL-terminated array of pointers? | |
262 | */ | |
263 | unsigned clNssArraySize( | |
264 | const void **array) | |
265 | { | |
266 | unsigned count = 0; | |
267 | if (array) { | |
268 | while (*array++) { | |
269 | count++; | |
270 | } | |
271 | } | |
272 | return count; | |
273 | } | |
274 | ||
275 | /* malloc a NULL-ed array of pointers of size num+1 */ | |
276 | void **clNssNullArray( | |
277 | uint32 num, | |
278 | SecNssCoder &coder) | |
279 | { | |
280 | unsigned len = (num + 1) * sizeof(void *); | |
281 | void **p = (void **)coder.malloc(len); | |
282 | memset(p, 0, len); | |
283 | return p; | |
284 | } | |
285 | ||
286 | /* | |
287 | * GIven a CSSM_DATA containing a decoded BIT_STRING, | |
288 | * convert to a KeyUsage. | |
289 | */ | |
290 | CE_KeyUsage clBitStringToKeyUsage( | |
291 | const CSSM_DATA &cdata) | |
292 | { | |
293 | unsigned toCopy = (cdata.Length + 7) / 8; | |
294 | if(toCopy > 2) { | |
295 | /* I hope I never see this... */ | |
296 | clErrorLog("clBitStringToKeyUsage: KeyUsage larger than 2 bytes!"); | |
297 | toCopy = 2; | |
298 | } | |
299 | unsigned char bits[2] = {0, 0}; | |
300 | memmove(bits, cdata.Data, toCopy); | |
301 | CE_KeyUsage usage = (((unsigned)bits[0]) << 8) | bits[1]; | |
302 | return usage; | |
303 | } | |
304 | ||
305 | CSSM_ALGORITHMS CL_oidToAlg( | |
306 | const CSSM_OID &oid) | |
307 | { | |
308 | CSSM_ALGORITHMS alg; | |
309 | bool found = cssmOidToAlg(&oid, &alg); | |
310 | if(!found) { | |
311 | clErrorLog("CL_oidToAlg: unknown alg\n"); | |
312 | CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); | |
313 | } | |
314 | return alg; | |
315 | } | |
316 | ||
317 | #pragma mark ----- copy CSSM_X509_ALGORITHM_IDENTIFIER ----- | |
318 | ||
319 | /* | |
320 | * Copy CSSM_X509_ALGORITHM_IDENTIFIER, same format (NSS and CSSM). | |
321 | */ | |
322 | void CL_copyAlgId( | |
323 | const CSSM_X509_ALGORITHM_IDENTIFIER &srcAlgId, | |
324 | CSSM_X509_ALGORITHM_IDENTIFIER &dstAlgId, | |
325 | Allocator &alloc) | |
326 | { | |
327 | clAllocCopyData(alloc, srcAlgId.algorithm, dstAlgId.algorithm); | |
328 | clAllocCopyData(alloc, srcAlgId.parameters, dstAlgId.parameters); | |
329 | } | |
330 | ||
331 | void CL_freeCssmAlgId( | |
332 | CSSM_X509_ALGORITHM_IDENTIFIER *cdsaObj, // optional | |
333 | Allocator &alloc) | |
334 | { | |
335 | if(cdsaObj == NULL) { | |
336 | return; | |
337 | } | |
338 | alloc.free(cdsaObj->algorithm.Data); | |
339 | alloc.free(cdsaObj->parameters.Data); | |
340 | memset(cdsaObj, 0, sizeof(CSSM_X509_ALGORITHM_IDENTIFIER)); | |
341 | } | |
342 | ||
343 | ||
344 | #pragma mark ----- CSSM_X509_TIME <--> NSS format ----- | |
345 | ||
346 | /* | |
347 | * Map the tag associated with a choice of DirectoryString elements to | |
348 | * a template array for encoding/decoding that string type. | |
349 | * Contrary to RFC2459, we allow the IA5String type, which is actually | |
350 | * used in the real world (cf. the email address in Thawte's serverbasic | |
351 | * cert). | |
352 | */ | |
353 | ||
354 | /* The template chooser does the work here */ | |
355 | ||
356 | bool CL_nssTimeToCssm( | |
357 | const NSS_TaggedItem &nssTime, | |
358 | CSSM_X509_TIME &cssmObj, | |
359 | Allocator &alloc) | |
360 | { | |
361 | cssmObj.timeType = nssTime.tag; | |
362 | clAllocCopyData(alloc, nssTime.item, cssmObj.time); | |
363 | return true; | |
364 | } | |
365 | ||
366 | /* | |
367 | * CSSM time to NSS time. | |
368 | */ | |
369 | void CL_cssmTimeToNss( | |
370 | const CSSM_X509_TIME &cssmTime, | |
371 | NSS_TaggedItem &nssTime, | |
372 | SecNssCoder &coder) | |
373 | { | |
374 | nssTime.tag = cssmTime.timeType; | |
375 | coder.allocCopyItem(cssmTime.time, nssTime.item); | |
376 | } | |
377 | ||
378 | void CL_freeCssmTime( | |
379 | CSSM_X509_TIME *cssmTime, | |
380 | Allocator &alloc) | |
381 | { | |
382 | if(cssmTime == NULL) { | |
383 | return; | |
384 | } | |
385 | if(cssmTime->time.Data) { | |
386 | alloc.free(cssmTime->time.Data); | |
387 | } | |
388 | memset(cssmTime, 0, sizeof(CSSM_X509_TIME)); | |
389 | } | |
390 | ||
391 | ||
392 | #pragma mark ----- CSSM_X509_SUBJECT_PUBLIC_KEY_INFO <--> CSSM_KEY ----- | |
393 | ||
394 | /* | |
395 | * Copy a CSSM_X509_SUBJECT_PUBLIC_KEY_INFO. | |
396 | * | |
397 | * Same format (NSS and CSSM), EXCEPT: | |
398 | * | |
399 | * Objects which have just been NSS decoded or are about to be | |
400 | * NSS encoded have the subjectPublicKey.Length field in BITS | |
401 | * since this field is wrapped in a BIT STRING upon encoding. | |
402 | * | |
403 | * Caller tells us which format (bits or bytes) | |
404 | * to use for each of {src, dst}. | |
405 | */ | |
406 | void CL_copySubjPubKeyInfo( | |
407 | const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &srcInfo, | |
408 | bool srcInBits, | |
409 | CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &dstInfo, | |
410 | bool dstInBits, | |
411 | Allocator &alloc) | |
412 | { | |
413 | CL_copyAlgId(srcInfo.algorithm, dstInfo.algorithm, alloc); | |
414 | ||
415 | CSSM_DATA srcKey = srcInfo.subjectPublicKey; | |
416 | if(srcInBits) { | |
417 | srcKey.Length = (srcKey.Length + 7) / 8; | |
418 | } | |
419 | clAllocCopyData(alloc, srcKey, dstInfo.subjectPublicKey); | |
420 | if(dstInBits) { | |
421 | dstInfo.subjectPublicKey.Length *= 8; | |
422 | } | |
423 | } | |
424 | ||
425 | /* | |
426 | * Obtain a CSSM_KEY from a CSSM_X509_SUBJECT_PUBLIC_KEY_INFO, | |
427 | * inferring as much as we can from required fields | |
428 | * (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO) and extensions (for | |
429 | * KeyUse, obtained from the optional DecodedCert). | |
430 | */ | |
431 | CSSM_KEY_PTR CL_extractCSSMKeyNSS( | |
432 | const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &keyInfo, | |
433 | Allocator &alloc, | |
434 | const DecodedCert *decodedCert) // optional | |
435 | { | |
436 | CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR) alloc.malloc(sizeof(CSSM_KEY)); | |
437 | memset(cssmKey, 0, sizeof(CSSM_KEY)); | |
438 | CSSM_KEYHEADER &hdr = cssmKey->KeyHeader; | |
439 | CssmRemoteData keyData(alloc, cssmKey->KeyData); | |
440 | ||
441 | hdr.HeaderVersion = CSSM_KEYHEADER_VERSION; | |
442 | /* CspId blank */ | |
443 | hdr.BlobType = CSSM_KEYBLOB_RAW; | |
444 | hdr.AlgorithmId = CL_oidToAlg(keyInfo.algorithm.algorithm); | |
445 | hdr.KeyAttr = CSSM_KEYATTR_MODIFIABLE | CSSM_KEYATTR_EXTRACTABLE; | |
446 | ||
447 | /* | |
448 | * Format inferred from AlgorithmId. I have never seen these defined | |
449 | * anywhere, e.g., what's the format of an RSA public key in a cert? | |
450 | * X509 certainly doesn't say. However. the following two cases are | |
451 | * known to be correct. | |
452 | */ | |
453 | switch(hdr.AlgorithmId) { | |
454 | case CSSM_ALGID_RSA: | |
455 | hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1; | |
456 | break; | |
457 | case CSSM_ALGID_DSA: | |
458 | case CSSM_ALGID_ECDSA: | |
459 | case CSSM_ALGID_DH: | |
460 | case CSSM_ALGMODE_PKCS1_EME_OAEP: | |
461 | hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_X509; | |
462 | break; | |
463 | case CSSM_ALGID_FEE: | |
464 | /* CSSM_KEYBLOB_RAW_FORMAT_NONE --> DER encoded */ | |
465 | hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE; | |
466 | break; | |
467 | default: | |
468 | /* punt */ | |
469 | hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE; | |
470 | } | |
471 | hdr.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY; | |
472 | ||
473 | /* KeyUsage inferred from extensions */ | |
474 | if(decodedCert) { | |
475 | hdr.KeyUsage = decodedCert->inferKeyUsage(); | |
476 | } | |
477 | else { | |
478 | hdr.KeyUsage = CSSM_KEYUSE_ANY; | |
479 | } | |
480 | ||
481 | /* start/end date unknown, leave zero */ | |
482 | hdr.WrapAlgorithmId = CSSM_ALGID_NONE; | |
483 | hdr.WrapMode = CSSM_ALGMODE_NONE; | |
484 | ||
485 | switch(hdr.AlgorithmId) { | |
486 | case CSSM_ALGID_DSA: | |
487 | case CSSM_ALGID_ECDSA: | |
488 | case CSSM_ALGID_DH: | |
489 | case CSSM_ALGMODE_PKCS1_EME_OAEP: | |
490 | { | |
491 | /* | |
492 | * Just encode the whole subject public key info blob. | |
493 | * NOTE we're assuming that the keyInfo.subjectPublicKey | |
494 | * field is in the NSS_native BITSTRING format, i.e., | |
495 | * its Length field is in bits and we don't have to adjust. | |
496 | */ | |
497 | PRErrorCode prtn = SecNssEncodeItemOdata(&keyInfo, | |
498 | kSecAsn1SubjectPublicKeyInfoTemplate, keyData); | |
499 | if(prtn) { | |
500 | clErrorLog("extractCSSMKey: error on reencode\n"); | |
501 | CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR); | |
502 | } | |
503 | break; | |
504 | } | |
505 | default: | |
506 | /* | |
507 | * RSA, FEE for now. | |
508 | * keyInfo.subjectPublicKey (in BITS) ==> KeyData | |
509 | */ | |
510 | keyData.copy(keyInfo.subjectPublicKey.Data, | |
511 | (keyInfo.subjectPublicKey.Length + 7) / 8); | |
512 | } | |
513 | ||
514 | /* | |
515 | * LogicalKeySizeInBits - ask the CSP | |
516 | */ | |
517 | CSSM_CSP_HANDLE cspHand = getGlobalCspHand(true); | |
518 | CSSM_KEY_SIZE keySize; | |
519 | CSSM_RETURN crtn; | |
520 | crtn = CSSM_QueryKeySizeInBits(cspHand, CSSM_INVALID_HANDLE, cssmKey, | |
521 | &keySize); | |
522 | switch(crtn) { | |
523 | default: | |
524 | CssmError::throwMe(crtn); | |
525 | case CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE: | |
526 | /* | |
527 | * This is how the CSP indicates a "partial" public key, | |
528 | * with a valid public key value but no alg-specific | |
529 | * parameters (currently, DSA only). | |
530 | */ | |
531 | hdr.KeyAttr |= CSSM_KEYATTR_PARTIAL; | |
532 | /* and drop thru */ | |
533 | case CSSM_OK: | |
534 | cssmKey->KeyHeader.LogicalKeySizeInBits = | |
535 | keySize.LogicalKeySizeInBits; | |
536 | break; | |
537 | } | |
538 | ||
539 | keyData.release(); | |
540 | return cssmKey; | |
541 | } | |
542 | ||
543 | /* | |
544 | * Set up a encoded NULL for CSSM_X509_ALGORITHM_IDENTIFIER.parameters. | |
545 | */ | |
546 | void CL_nullAlgParams( | |
547 | CSSM_X509_ALGORITHM_IDENTIFIER &algId) | |
548 | { | |
549 | static const uint8 encNull[2] = { SEC_ASN1_NULL, 0 }; | |
550 | CSSM_DATA encNullData; | |
551 | encNullData.Data = (uint8 *)encNull; | |
552 | encNullData.Length = 2; | |
553 | ||
554 | algId.parameters = encNullData; | |
555 | } | |
556 | ||
557 | /* | |
558 | * Convert a CSSM_KEY to a CSSM_X509_SUBJECT_PUBLIC_KEY_INFO. The | |
559 | * CSSM key must be in raw format and with a specific blob format. | |
560 | * -- RSA keys have to be CSSM_KEYBLOB_RAW_FORMAT_PKCS1 | |
561 | * -- DSA keys have to be CSSM_KEYBLOB_RAW_FORMAT_X509 | |
562 | * -- ECDSA keys have to be CSSM_KEYBLOB_RAW_FORMAT_X509 | |
563 | */ | |
564 | void CL_CSSMKeyToSubjPubKeyInfoNSS( | |
565 | const CSSM_KEY &cssmKey, | |
566 | CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &nssKeyInfo, | |
567 | SecNssCoder &coder) | |
568 | { | |
569 | const CSSM_KEYHEADER &hdr = cssmKey.KeyHeader; | |
570 | if(hdr.BlobType != CSSM_KEYBLOB_RAW) { | |
571 | clErrorLog("CL SetField: must specify RAW key blob\n"); | |
572 | CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT); | |
573 | } | |
574 | memset(&nssKeyInfo, 0, sizeof(nssKeyInfo)); | |
575 | ||
576 | /* algorithm and format dependent from here... */ | |
577 | switch(hdr.AlgorithmId) { | |
578 | case CSSM_ALGID_RSA: | |
579 | if(hdr.Format != CSSM_KEYBLOB_RAW_FORMAT_PKCS1) { | |
580 | clErrorLog("CL SetField: RSA key must be in PKCS1 format\n"); | |
581 | CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT); | |
582 | } | |
583 | /* and fall thru */ | |
584 | default: | |
585 | { | |
586 | /* Key header's algorithm --> OID */ | |
587 | const CSSM_OID *oid = cssmAlgToOid(hdr.AlgorithmId); | |
588 | if(oid == NULL) { | |
589 | clErrorLog("CL SetField: Unknown key algorithm\n"); | |
590 | CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); | |
591 | } | |
592 | CSSM_X509_ALGORITHM_IDENTIFIER &algId = nssKeyInfo.algorithm; | |
593 | coder.allocCopyItem(*oid, algId.algorithm); | |
594 | ||
595 | /* NULL algorithm parameters, always in this case */ | |
596 | CL_nullAlgParams(algId); | |
597 | ||
598 | /* Copy key bits, destination is a BIT STRING */ | |
599 | coder.allocCopyItem(cssmKey.KeyData, nssKeyInfo.subjectPublicKey); | |
600 | nssKeyInfo.subjectPublicKey.Length *= 8; | |
601 | break; | |
602 | } | |
603 | case CSSM_ALGID_DSA: | |
604 | case CSSM_ALGID_ECDSA: | |
605 | if(hdr.Format != CSSM_KEYBLOB_RAW_FORMAT_X509) { | |
606 | clErrorLog("CL SetField: DSA/ECDSA key must be in X509 format\n"); | |
607 | CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT); | |
608 | } | |
609 | ||
610 | /* | |
611 | * All we do is decode the whole key blob into the | |
612 | * SubjectPublicKeyInfo. | |
613 | */ | |
614 | if(coder.decodeItem(cssmKey.KeyData, | |
615 | kSecAsn1SubjectPublicKeyInfoTemplate, | |
616 | &nssKeyInfo)) { | |
617 | clErrorLog("CL SetField: Error decoding DSA public key\n"); | |
618 | CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT); | |
619 | } | |
620 | break; | |
621 | } | |
622 | } | |
623 | ||
624 | void CL_freeCSSMKey( | |
625 | CSSM_KEY_PTR cssmKey, | |
626 | Allocator &alloc, | |
627 | bool freeTop) | |
628 | { | |
629 | if(cssmKey == NULL) { | |
630 | return; | |
631 | } | |
632 | alloc.free(cssmKey->KeyData.Data); | |
633 | memset(cssmKey, 0, sizeof(CSSM_KEY)); | |
634 | if(freeTop) { | |
635 | alloc.free(cssmKey); | |
636 | } | |
637 | } | |
638 | ||
639 | #pragma mark ----- CE_AuthorityKeyID <--> NSS_AuthorityKeyId ----- | |
640 | ||
641 | void CL_cssmAuthorityKeyIdToNss( | |
642 | const CE_AuthorityKeyID &cdsaObj, | |
643 | NSS_AuthorityKeyId &nssObj, | |
644 | SecNssCoder &coder) | |
645 | { | |
646 | memset(&nssObj, 0, sizeof(nssObj)); | |
647 | if(cdsaObj.keyIdentifierPresent) { | |
648 | nssObj.keyIdentifier = (CSSM_DATA_PTR)coder.malloc(sizeof(CSSM_DATA)); | |
649 | coder.allocCopyItem(cdsaObj.keyIdentifier, *nssObj.keyIdentifier); | |
650 | } | |
651 | if(cdsaObj.generalNamesPresent ) { | |
652 | /* GeneralNames, the hard one */ | |
653 | CL_cssmGeneralNamesToNss(*cdsaObj.generalNames, | |
654 | nssObj.genNames, coder); | |
655 | } | |
656 | if(cdsaObj.serialNumberPresent) { | |
657 | coder.allocCopyItem(cdsaObj.serialNumber,nssObj.serialNumber); | |
658 | } | |
659 | } | |
660 | ||
661 | void CL_nssAuthorityKeyIdToCssm( | |
662 | const NSS_AuthorityKeyId &nssObj, | |
663 | CE_AuthorityKeyID &cdsaObj, | |
664 | SecNssCoder &coder, // for temp decoding | |
665 | Allocator &alloc) | |
666 | { | |
667 | if(nssObj.keyIdentifier != NULL) { | |
668 | cdsaObj.keyIdentifierPresent = CSSM_TRUE; | |
669 | clAllocCopyData(alloc, *nssObj.keyIdentifier, cdsaObj.keyIdentifier); | |
670 | } | |
671 | if(nssObj.genNames.names != NULL) { | |
672 | /* GeneralNames, the hard one */ | |
673 | cdsaObj.generalNamesPresent = CSSM_TRUE; | |
674 | cdsaObj.generalNames = | |
675 | (CE_GeneralNames *)alloc.malloc(sizeof(CE_GeneralNames)); | |
676 | CL_nssGeneralNamesToCssm(nssObj.genNames, | |
677 | *cdsaObj.generalNames, | |
678 | coder, | |
679 | alloc); | |
680 | } | |
681 | if(nssObj.serialNumber.Data != NULL) { | |
682 | cdsaObj.serialNumberPresent = CSSM_TRUE; | |
683 | clAllocCopyData(alloc, nssObj.serialNumber, cdsaObj.serialNumber); | |
684 | } | |
685 | } | |
686 | ||
687 | #pragma mark ----- CE_AuthorityInfoAccess <--> NSS_AuthorityInfoAccess ----- | |
688 | ||
689 | void CL_cssmInfoAccessToNss( | |
690 | const CE_AuthorityInfoAccess &cdsaObj, | |
691 | NSS_AuthorityInfoAccess &nssObj, | |
692 | SecNssCoder &coder) | |
693 | { | |
694 | memset(&nssObj, 0, sizeof(nssObj)); | |
695 | uint32 numDescs = cdsaObj.numAccessDescriptions; | |
696 | nssObj.accessDescriptions = (NSS_AccessDescription **)clNssNullArray(numDescs, coder); | |
697 | ||
698 | for(unsigned dex=0; dex<numDescs; dex++) { | |
699 | nssObj.accessDescriptions[dex] = coder.mallocn<NSS_AccessDescription>(); | |
700 | CE_AccessDescription *src = &cdsaObj.accessDescriptions[dex]; | |
701 | NSS_AccessDescription *dst = nssObj.accessDescriptions[dex]; | |
702 | coder.allocCopyItem(src->accessMethod, dst->accessMethod); | |
703 | ||
704 | /* Convert general name, then encode it into destination */ | |
705 | NSS_GeneralName nssGenName; | |
706 | CL_cssmGeneralNameToNss(src->accessLocation, nssGenName, coder); | |
707 | PRErrorCode prtn = coder.encodeItem(&nssGenName, kSecAsn1GeneralNameTemplate, | |
708 | dst->encodedAccessLocation); | |
709 | if(prtn) { | |
710 | clErrorLog("CL_cssmInfoAccessToNss: encode error\n"); | |
711 | CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR); | |
712 | } | |
713 | } | |
714 | } | |
715 | ||
716 | void CL_infoAccessToCssm( | |
717 | const NSS_AuthorityInfoAccess &nssObj, | |
718 | CE_AuthorityInfoAccess &cdsaObj, | |
719 | SecNssCoder &coder, // for temp decoding | |
720 | Allocator &alloc) | |
721 | { | |
722 | memset(&cdsaObj, 0, sizeof(cdsaObj)); | |
723 | unsigned numDescs = clNssArraySize((const void **)nssObj.accessDescriptions); | |
724 | if(numDescs == 0) { | |
725 | return; | |
726 | } | |
727 | cdsaObj.accessDescriptions = (CE_AccessDescription *)alloc.malloc( | |
728 | numDescs * sizeof(CE_AccessDescription)); | |
729 | cdsaObj.numAccessDescriptions = numDescs; | |
730 | for(unsigned dex=0; dex<numDescs; dex++) { | |
731 | CE_AccessDescription *dst = &cdsaObj.accessDescriptions[dex]; | |
732 | NSS_AccessDescription *src = nssObj.accessDescriptions[dex]; | |
733 | clAllocCopyData(alloc, src->accessMethod, dst->accessMethod); | |
734 | ||
735 | /* decode the general name */ | |
736 | NSS_GeneralName nssGenName; | |
737 | memset(&nssGenName, 0, sizeof(nssGenName)); | |
738 | PRErrorCode prtn = coder.decodeItem(src->encodedAccessLocation, | |
739 | kSecAsn1GeneralNameTemplate, &nssGenName); | |
740 | if(prtn) { | |
741 | clErrorLog("***Error decoding NSS_AuthorityInfoAccess.accessLocation\n"); | |
742 | CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); | |
743 | } | |
744 | ||
745 | /* then convert the result to CSSM */ | |
746 | CL_nssGeneralNameToCssm(nssGenName, dst->accessLocation, coder, alloc); | |
747 | } | |
748 | } | |
749 | ||
750 | void CL_freeInfoAccess( | |
751 | CE_AuthorityInfoAccess &cssmInfo, | |
752 | Allocator &alloc) | |
753 | { | |
754 | uint32 numDescs = cssmInfo.numAccessDescriptions; | |
755 | for(unsigned dex=0; dex<numDescs; dex++) { | |
756 | CE_AccessDescription *dst = &cssmInfo.accessDescriptions[dex]; | |
757 | alloc.free(dst->accessMethod.Data); | |
758 | CL_freeCssmGeneralName(dst->accessLocation, alloc); | |
759 | } | |
760 | alloc.free(cssmInfo.accessDescriptions); | |
761 | } | |
762 | ||
763 | ||
764 | #pragma mark ----- CE_QC_Statements <--> NSS_QC_Statements ----- | |
765 | ||
766 | void CL_cssmQualCertStatementsToNss( | |
767 | const CE_QC_Statements &cdsaObj, | |
768 | NSS_QC_Statements &nssObj, | |
769 | SecNssCoder &coder) | |
770 | { | |
771 | memset(&nssObj, 0, sizeof(nssObj)); | |
772 | uint32 numQcs = cdsaObj.numQCStatements; | |
773 | nssObj.qcStatements = | |
774 | (NSS_QC_Statement **)clNssNullArray(numQcs, coder); | |
775 | for(uint32 dex=0; dex<numQcs; dex++) { | |
776 | nssObj.qcStatements[dex] = (NSS_QC_Statement *) | |
777 | coder.malloc(sizeof(NSS_QC_Statement)); | |
778 | NSS_QC_Statement *dst = nssObj.qcStatements[dex]; | |
779 | CE_QC_Statement *src = &cdsaObj.qcStatements[dex]; | |
780 | memset(dst, 0, sizeof(*dst)); | |
781 | coder.allocCopyItem(src->statementId, dst->statementId); | |
782 | if(src->semanticsInfo) { | |
783 | if(src->otherInfo) { | |
784 | /* this is either/or, not both */ | |
785 | CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER); | |
786 | } | |
787 | ||
788 | /* encode this CE_SemanticsInformation */ | |
789 | CE_SemanticsInformation *srcSI = src->semanticsInfo; | |
790 | NSS_SemanticsInformation dstSI; | |
791 | memset(&dstSI, 0, sizeof(dstSI)); | |
792 | if(srcSI->semanticsIdentifier) { | |
793 | dstSI.semanticsIdentifier = (CSSM_DATA_PTR)coder.malloc(sizeof(CSSM_DATA)); | |
794 | coder.allocCopyItem(*srcSI->semanticsIdentifier, | |
795 | *dstSI.semanticsIdentifier); | |
796 | } | |
797 | if(srcSI->nameRegistrationAuthorities) { | |
798 | dstSI.nameRegistrationAuthorities = | |
799 | (NSS_GeneralNames *)coder.malloc(sizeof(NSS_GeneralNames)); | |
800 | CL_cssmGeneralNamesToNss(*srcSI->nameRegistrationAuthorities, | |
801 | *dstSI.nameRegistrationAuthorities, coder); | |
802 | } | |
803 | PRErrorCode prtn = coder.encodeItem(&dstSI, kSecAsn1SemanticsInformationTemplate, | |
804 | dst->info); | |
805 | if(prtn) { | |
806 | clErrorLog("CL_cssmQualCertStatementsToNss: encode error\n"); | |
807 | CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR); | |
808 | } | |
809 | ||
810 | } | |
811 | if(src->otherInfo) { | |
812 | /* drop in as ASN_ANY */ | |
813 | coder.allocCopyItem(*src->otherInfo, dst->info); | |
814 | } | |
815 | } | |
816 | } | |
817 | ||
818 | void CL_qualCertStatementsToCssm( | |
819 | const NSS_QC_Statements &nssObj, | |
820 | CE_QC_Statements &cdsaObj, | |
821 | SecNssCoder &coder, // for temp decoding | |
822 | Allocator &alloc) | |
823 | { | |
824 | memset(&cdsaObj, 0, sizeof(cdsaObj)); | |
825 | unsigned numQcs = clNssArraySize((const void **)nssObj.qcStatements); | |
826 | if(numQcs == 0) { | |
827 | return; | |
828 | } | |
829 | cdsaObj.qcStatements = (CE_QC_Statement *)alloc.malloc( | |
830 | numQcs * sizeof(CE_AccessDescription)); | |
831 | cdsaObj.numQCStatements = numQcs; | |
832 | for(unsigned dex=0; dex<numQcs; dex++) { | |
833 | CE_QC_Statement *dst = &cdsaObj.qcStatements[dex]; | |
834 | NSS_QC_Statement *src = nssObj.qcStatements[dex]; | |
835 | ||
836 | memset(dst, 0, sizeof(*dst)); | |
837 | clAllocCopyData(alloc, src->statementId, dst->statementId); | |
838 | ||
839 | /* | |
840 | * Whether the optional info is a SemanticsInformation or is uninterpreted | |
841 | * DER data depends on statementId. | |
842 | */ | |
843 | if(src->info.Data) { | |
844 | if(clCompareCssmData(&src->statementId, &CSSMOID_OID_QCS_SYNTAX_V2)) { | |
845 | NSS_SemanticsInformation srcSI; | |
846 | memset(&srcSI, 0, sizeof(srcSI)); | |
847 | ||
848 | /* decode info as a NSS_SemanticsInformation */ | |
849 | PRErrorCode prtn = coder.decodeItem(src->info, | |
850 | kSecAsn1SemanticsInformationTemplate, &srcSI); | |
851 | if(prtn) { | |
852 | clErrorLog("***Error decoding CE_SemanticsInformation\n"); | |
853 | CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); | |
854 | } | |
855 | ||
856 | /* NSS_SemanticsInformation --> CE_SemanticsInformation */ | |
857 | dst->semanticsInfo = | |
858 | (CE_SemanticsInformation *)alloc.malloc(sizeof(CE_SemanticsInformation)); | |
859 | CE_SemanticsInformation *dstSI = dst->semanticsInfo; | |
860 | memset(dstSI, 0, sizeof(*dstSI)); | |
861 | if(srcSI.semanticsIdentifier) { | |
862 | dstSI->semanticsIdentifier = (CSSM_OID *)alloc.malloc(sizeof(CSSM_OID)); | |
863 | clAllocCopyData(alloc, *srcSI.semanticsIdentifier, *dstSI->semanticsIdentifier); | |
864 | } | |
865 | if(srcSI.nameRegistrationAuthorities) { | |
866 | dstSI->nameRegistrationAuthorities = | |
867 | (CE_NameRegistrationAuthorities *)alloc.malloc( | |
868 | sizeof(CE_NameRegistrationAuthorities)); | |
869 | CL_nssGeneralNamesToCssm(*srcSI.nameRegistrationAuthorities, | |
870 | *dstSI->nameRegistrationAuthorities, | |
871 | coder, | |
872 | alloc); | |
873 | } | |
874 | } | |
875 | else { | |
876 | dst->otherInfo = (CSSM_DATA_PTR)alloc.malloc(sizeof(CSSM_DATA)); | |
877 | clAllocCopyData(alloc, src->info, *dst->otherInfo); | |
878 | } | |
879 | } | |
880 | } | |
881 | } | |
882 | ||
883 | void CL_freeQualCertStatements( | |
884 | CE_QC_Statements &cssmQCs, | |
885 | Allocator &alloc) | |
886 | { | |
887 | uint32 numQCs = cssmQCs.numQCStatements; | |
888 | for(unsigned dex=0; dex<numQCs; dex++) { | |
889 | CE_QC_Statement *dst = &cssmQCs.qcStatements[dex]; | |
890 | alloc.free(dst->statementId.Data); | |
891 | if(dst->semanticsInfo) { | |
892 | CE_SemanticsInformation *si = dst->semanticsInfo; | |
893 | if(si->semanticsIdentifier) { | |
894 | alloc.free(si->semanticsIdentifier->Data); | |
895 | alloc.free(si->semanticsIdentifier); | |
896 | } | |
897 | if(si->nameRegistrationAuthorities) { | |
898 | CL_freeCssmGeneralNames(si->nameRegistrationAuthorities, alloc); | |
899 | alloc.free(si->nameRegistrationAuthorities); | |
900 | } | |
901 | alloc.free(si); | |
902 | } | |
903 | if(dst->otherInfo) { | |
904 | alloc.free(dst->otherInfo->Data); | |
905 | alloc.free(dst->otherInfo); | |
906 | } | |
907 | } | |
908 | alloc.free(cssmQCs.qcStatements); | |
909 | } | |
910 | ||
911 | #pragma mark ----- decode/encode CE_DistributionPointName ----- | |
912 | ||
913 | /* This is always a DER-encoded blob at the NSS level */ | |
914 | void CL_decodeDistributionPointName( | |
915 | const CSSM_DATA &nssBlob, | |
916 | CE_DistributionPointName &cssmDpn, | |
917 | SecNssCoder &coder, | |
918 | Allocator &alloc) | |
919 | { | |
920 | memset(&cssmDpn, 0, sizeof(CE_DistributionPointName)); | |
921 | if(nssBlob.Length == 0) { | |
922 | clErrorLog("***CL_decodeDistributionPointName: bad PointName\n"); | |
923 | CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); | |
924 | } | |
925 | unsigned char tag = nssBlob.Data[0] & SEC_ASN1_TAGNUM_MASK; | |
926 | switch(tag) { | |
927 | case NSS_DIST_POINT_FULL_NAME_TAG: | |
928 | { | |
929 | /* decode to temp coder memory */ | |
930 | NSS_GeneralNames gnames; | |
931 | gnames.names = NULL; | |
932 | if(coder.decodeItem(nssBlob, kSecAsn1DistPointFullNameTemplate, | |
933 | &gnames)) { | |
934 | clErrorLog("***Error decoding DistPointFullName\n"); | |
935 | CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); | |
936 | } | |
937 | ||
938 | cssmDpn.nameType = CE_CDNT_FullName; | |
939 | cssmDpn.dpn.fullName = (CE_GeneralNames *)alloc.malloc( | |
940 | sizeof(CE_GeneralNames)); | |
941 | ||
942 | /* copy out to caller */ | |
943 | CL_nssGeneralNamesToCssm(gnames, | |
944 | *cssmDpn.dpn.fullName, coder, alloc); | |
945 | break; | |
946 | } | |
947 | case NSS_DIST_POINT_RDN_TAG: | |
948 | { | |
949 | /* decode to temp coder memory */ | |
950 | NSS_RDN rdn; | |
951 | memset(&rdn, 0, sizeof(rdn)); | |
952 | if(coder.decodeItem(nssBlob, kSecAsn1DistPointRDNTemplate, | |
953 | &rdn)) { | |
954 | clErrorLog("***Error decoding DistPointRDN\n"); | |
955 | CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); | |
956 | } | |
957 | ||
958 | cssmDpn.nameType = CE_CDNT_NameRelativeToCrlIssuer; | |
959 | cssmDpn.dpn.rdn = (CSSM_X509_RDN_PTR)alloc.malloc( | |
960 | sizeof(CSSM_X509_RDN)); | |
961 | ||
962 | /* copy out to caller */ | |
963 | CL_nssRdnToCssm(rdn, *cssmDpn.dpn.rdn, alloc, coder); | |
964 | break; | |
965 | } | |
966 | default: | |
967 | clErrorLog("***Bad CE_DistributionPointName tag\n"); | |
968 | CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); | |
969 | } | |
970 | } | |
971 | ||
972 | void CL_encodeDistributionPointName( | |
973 | CE_DistributionPointName &cpoint, | |
974 | CSSM_DATA &npoint, | |
975 | SecNssCoder &coder) | |
976 | { | |
977 | const SecAsn1Template *templ = NULL; | |
978 | NSS_GeneralNames gnames; | |
979 | NSS_RDN rdn; | |
980 | void *encodeSrc = NULL; | |
981 | ||
982 | /* | |
983 | * Our job is to convert one of two incoming aggregate types | |
984 | * into NSS format, then encode the result into npoint. | |
985 | */ | |
986 | switch(cpoint.nameType) { | |
987 | case CE_CDNT_FullName: | |
988 | CL_cssmGeneralNamesToNss(*cpoint.dpn.fullName, | |
989 | gnames, coder); | |
990 | encodeSrc = &gnames; | |
991 | templ = kSecAsn1DistPointFullNameTemplate; | |
992 | break; | |
993 | ||
994 | case CE_CDNT_NameRelativeToCrlIssuer: | |
995 | CL_cssmRdnToNss(*cpoint.dpn.rdn, rdn, coder); | |
996 | encodeSrc = &rdn; | |
997 | templ = kSecAsn1DistPointRDNTemplate; | |
998 | break; | |
999 | default: | |
1000 | clErrorLog("CL_encodeDistributionPointName: bad nameType\n"); | |
1001 | CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG); | |
1002 | } | |
1003 | if(coder.encodeItem(encodeSrc, templ, npoint)) { | |
1004 | clErrorLog("CL_encodeDistributionPointName: encode error\n"); | |
1005 | CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR); | |
1006 | } | |
1007 | } | |
1008 | ||
1009 | ||
1010 | #pragma mark --- CE_CRLDistPointsSyntax <--> NSS_CRLDistributionPoints --- | |
1011 | ||
1012 | void CL_cssmDistPointsToNss( | |
1013 | const CE_CRLDistPointsSyntax &cdsaObj, | |
1014 | NSS_CRLDistributionPoints &nssObj, | |
1015 | SecNssCoder &coder) | |
1016 | { | |
1017 | memset(&nssObj, 0, sizeof(nssObj)); | |
1018 | unsigned numPoints = cdsaObj.numDistPoints; | |
1019 | if(numPoints == 0) { | |
1020 | return; | |
1021 | } | |
1022 | nssObj.distPoints = | |
1023 | (NSS_DistributionPoint **)clNssNullArray(numPoints, coder); | |
1024 | for(unsigned dex=0; dex<numPoints; dex++) { | |
1025 | nssObj.distPoints[dex] = (NSS_DistributionPoint *) | |
1026 | coder.malloc(sizeof(NSS_DistributionPoint)); | |
1027 | NSS_DistributionPoint *npoint = nssObj.distPoints[dex]; | |
1028 | memset(npoint, 0, sizeof(NSS_DistributionPoint)); | |
1029 | CE_CRLDistributionPoint *cpoint = &cdsaObj.distPoints[dex]; | |
1030 | ||
1031 | /* all fields are optional */ | |
1032 | if(cpoint->distPointName) { | |
1033 | /* encode and drop into ASN_ANY slot */ | |
1034 | npoint->distPointName = (CSSM_DATA *) | |
1035 | coder.malloc(sizeof(CSSM_DATA)); | |
1036 | CL_encodeDistributionPointName(*cpoint->distPointName, | |
1037 | *npoint->distPointName, coder); | |
1038 | ||
1039 | } | |
1040 | ||
1041 | if(cpoint->reasonsPresent) { | |
1042 | /* bit string, presumed max length 8 bits */ | |
1043 | coder.allocItem(npoint->reasons, 1); | |
1044 | npoint->reasons.Data[0] = cpoint->reasons; | |
1045 | /* adjust for bit string length */ | |
1046 | npoint->reasons.Length = 8; | |
1047 | } | |
1048 | ||
1049 | if(cpoint->crlIssuer) { | |
1050 | CL_cssmGeneralNamesToNss(*cpoint->crlIssuer, | |
1051 | npoint->crlIssuer, coder); | |
1052 | } | |
1053 | } | |
1054 | } | |
1055 | ||
1056 | void CL_nssDistPointsToCssm( | |
1057 | const NSS_CRLDistributionPoints &nssObj, | |
1058 | CE_CRLDistPointsSyntax &cdsaObj, | |
1059 | SecNssCoder &coder, // for temp decoding | |
1060 | Allocator &alloc) | |
1061 | { | |
1062 | memset(&cdsaObj, 0, sizeof(cdsaObj)); | |
1063 | unsigned numPoints = clNssArraySize((const void **)nssObj.distPoints); | |
1064 | if(numPoints == 0) { | |
1065 | return; | |
1066 | } | |
1067 | ||
1068 | unsigned len = sizeof(CE_CRLDistributionPoint) * numPoints; | |
1069 | cdsaObj.distPoints = (CE_CRLDistributionPoint *)alloc.malloc(len); | |
1070 | memset(cdsaObj.distPoints, 0, len); | |
1071 | cdsaObj.numDistPoints = numPoints; | |
1072 | ||
1073 | for(unsigned dex=0; dex<numPoints; dex++) { | |
1074 | CE_CRLDistributionPoint &cpoint = cdsaObj.distPoints[dex]; | |
1075 | NSS_DistributionPoint &npoint = *(nssObj.distPoints[dex]); | |
1076 | ||
1077 | /* All three fields are optional */ | |
1078 | if(npoint.distPointName != NULL) { | |
1079 | /* Drop in a CE_DistributionPointName */ | |
1080 | CE_DistributionPointName *cname = | |
1081 | (CE_DistributionPointName *)alloc.malloc( | |
1082 | sizeof(CE_DistributionPointName)); | |
1083 | memset(cname, 0, sizeof(*cname)); | |
1084 | cpoint.distPointName = cname; | |
1085 | ||
1086 | /* | |
1087 | * This one is currently still encoded; we have to peek | |
1088 | * at its tag and decode accordingly. | |
1089 | */ | |
1090 | CL_decodeDistributionPointName(*npoint.distPointName, | |
1091 | *cname, coder, alloc); | |
1092 | } | |
1093 | ||
1094 | if(npoint.reasons.Data != NULL) { | |
1095 | /* careful, it's a bit string */ | |
1096 | if(npoint.reasons.Length > 8) { | |
1097 | clErrorLog("***CL_nssDistPointsToCssm: Malformed reasons\n"); | |
1098 | CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); | |
1099 | } | |
1100 | cpoint.reasonsPresent = CSSM_TRUE; | |
1101 | if(npoint.reasons.Length != 0) { | |
1102 | cpoint.reasons = npoint.reasons.Data[0]; | |
1103 | } | |
1104 | } | |
1105 | ||
1106 | if(npoint.crlIssuer.names != NULL) { | |
1107 | /* Cook up a new CE_GeneralNames */ | |
1108 | cpoint.crlIssuer = | |
1109 | (CE_GeneralNames *)alloc.malloc(sizeof(CE_GeneralNames)); | |
1110 | CL_nssGeneralNamesToCssm(npoint.crlIssuer, *cpoint.crlIssuer, | |
1111 | coder, alloc); | |
1112 | } | |
1113 | } | |
1114 | } | |
1115 | ||
1116 | #pragma mark ----- IssuingDistributionPoint ----- | |
1117 | ||
1118 | void CL_nssIssuingDistPointToCssm( | |
1119 | NSS_IssuingDistributionPoint *nssIdp, | |
1120 | CE_IssuingDistributionPoint *cssmIdp, | |
1121 | SecNssCoder &coder, | |
1122 | Allocator &alloc) | |
1123 | { | |
1124 | /* All fields optional */ | |
1125 | memset(cssmIdp, 0, sizeof(*cssmIdp)); | |
1126 | if(nssIdp->distPointName) { | |
1127 | CE_DistributionPointName *cssmDp = (CE_DistributionPointName *) | |
1128 | alloc.malloc(sizeof(CE_DistributionPointName)); | |
1129 | ||
1130 | /* | |
1131 | * This one is currently still encoded; we have to peek | |
1132 | * at its tag and decode accordingly. | |
1133 | */ | |
1134 | CL_decodeDistributionPointName(*nssIdp->distPointName, | |
1135 | *cssmDp, coder, alloc); | |
1136 | cssmIdp->distPointName = cssmDp; | |
1137 | } | |
1138 | if(nssIdp->onlyUserCerts) { | |
1139 | cssmIdp->onlyUserCertsPresent = CSSM_TRUE; | |
1140 | cssmIdp->onlyUserCerts = clNssBoolToCssm(*nssIdp->onlyUserCerts); | |
1141 | } | |
1142 | if(nssIdp->onlyCACerts) { | |
1143 | cssmIdp->onlyCACertsPresent = CSSM_TRUE; | |
1144 | cssmIdp->onlyCACerts = clNssBoolToCssm(*nssIdp->onlyCACerts); | |
1145 | } | |
1146 | if(nssIdp->onlySomeReasons) { | |
1147 | cssmIdp->onlySomeReasonsPresent = CSSM_TRUE; | |
1148 | if(nssIdp->onlySomeReasons->Length > 0) { | |
1149 | cssmIdp->onlySomeReasons = *nssIdp->onlySomeReasons->Data; | |
1150 | } | |
1151 | else { | |
1152 | cssmIdp->onlySomeReasons = 0; | |
1153 | } | |
1154 | } | |
1155 | if(nssIdp->indirectCRL) { | |
1156 | cssmIdp->indirectCrlPresent = CSSM_TRUE; | |
1157 | cssmIdp->indirectCrl = clNssBoolToCssm(*nssIdp->indirectCRL); | |
1158 | } | |
1159 | } | |
1160 | ||
1161 | #pragma mark --- CE_NameConstraints <--> NSS_NameConstraints --- | |
1162 | ||
1163 | void CL_cssmNameConstraintsToNss( | |
1164 | const CE_NameConstraints &cdsaObj, | |
1165 | NSS_NameConstraints &nssObj, | |
1166 | SecNssCoder &coder) | |
1167 | { | |
1168 | //%%%FIXME tba | |
1169 | } | |
1170 | ||
1171 | void CL_nssNameConstraintsToCssm( | |
1172 | const NSS_NameConstraints &nssObj, | |
1173 | CE_NameConstraints &cdsaObj, | |
1174 | SecNssCoder &coder, // for temp decoding | |
1175 | Allocator &alloc) | |
1176 | { | |
1177 | //%%%FIXME tba | |
1178 | } | |
1179 | ||
1180 | void CL_freeCssmNameConstraints( | |
1181 | CE_NameConstraints *cssmNcs, | |
1182 | Allocator &alloc) | |
1183 | { | |
1184 | if(cssmNcs == NULL) { | |
1185 | return; | |
1186 | } | |
1187 | //%%%FIXME need to add a CL_freeCssmGeneralSubtrees function to clNameUtils{.h,.cpp} | |
1188 | #if 0 | |
1189 | switch(cssmDpn->nameType) { | |
1190 | case CE_CDNT_FullName: | |
1191 | CL_freeCssmGeneralNames(cssmDpn->dpn.fullName, alloc); | |
1192 | alloc.free(cssmDpn->dpn.fullName); | |
1193 | break; | |
1194 | case CE_CDNT_NameRelativeToCrlIssuer: | |
1195 | CL_freeX509Rdn(cssmDpn->dpn.rdn, alloc); | |
1196 | alloc.free(cssmDpn->dpn.rdn); | |
1197 | break; | |
1198 | } | |
1199 | #endif | |
1200 | memset(cssmNcs, 0, sizeof(*cssmNcs)); | |
1201 | } | |
1202 | ||
1203 | #pragma mark --- CE_PolicyMappings <--> NSS_PolicyMappings --- | |
1204 | ||
1205 | void CL_cssmPolicyMappingsToNss( | |
1206 | const CE_PolicyMappings &cdsaObj, | |
1207 | NSS_PolicyMappings &nssObj, | |
1208 | SecNssCoder &coder) | |
1209 | { | |
1210 | //%%%FIXME tba | |
1211 | } | |
1212 | ||
1213 | void CL_nssPolicyMappingsToCssm( | |
1214 | const NSS_PolicyMappings &nssObj, | |
1215 | CE_PolicyMappings &cdsaObj, | |
1216 | SecNssCoder &coder, // for temp decoding | |
1217 | Allocator &alloc) | |
1218 | { | |
1219 | //%%%FIXME tba | |
1220 | } | |
1221 | ||
1222 | void CL_freeCssmPolicyMappings( | |
1223 | CE_PolicyMappings *cssmPms, | |
1224 | Allocator &alloc) | |
1225 | { | |
1226 | if(cssmPms == NULL) { | |
1227 | return; | |
1228 | } | |
1229 | //%%%FIXME tba | |
1230 | ||
1231 | memset(cssmPms, 0, sizeof(*cssmPms)); | |
1232 | } | |
1233 | ||
1234 | #pragma mark --- CE_PolicyConstraints <--> NSS_PolicyConstraints --- | |
1235 | ||
1236 | void CL_cssmPolicyConstraintsToNss( | |
1237 | const CE_PolicyConstraints *cdsaObj, | |
1238 | NSS_PolicyConstraints *nssObj, | |
1239 | SecNssCoder &coder) | |
1240 | { | |
1241 | //%%%FIXME tba | |
1242 | } | |
1243 | ||
1244 | void CL_nssPolicyConstraintsToCssm( | |
1245 | const NSS_PolicyConstraints *nssObj, | |
1246 | CE_PolicyConstraints *cdsaObj, | |
1247 | SecNssCoder &coder, // for temp decoding | |
1248 | Allocator &alloc) | |
1249 | { | |
1250 | memset(cdsaObj, 0, sizeof(*cdsaObj)); | |
1251 | if(nssObj->requireExplicitPolicy.Data) { | |
1252 | cdsaObj->requireExplicitPolicyPresent = CSSM_TRUE; | |
1253 | cdsaObj->inhibitPolicyMapping = clDataToInt( | |
1254 | nssObj->requireExplicitPolicy, 0); | |
1255 | } | |
1256 | if(nssObj->inhibitPolicyMapping.Data) { | |
1257 | cdsaObj->inhibitPolicyMappingPresent = CSSM_TRUE; | |
1258 | cdsaObj->inhibitPolicyMapping = clDataToInt( | |
1259 | nssObj->inhibitPolicyMapping, 0); | |
1260 | } | |
1261 | } | |
1262 | ||
1263 | void CL_freeCssmPolicyConstraints( | |
1264 | CE_PolicyConstraints *cssmPcs, | |
1265 | Allocator &alloc) | |
1266 | { | |
1267 | if(cssmPcs == NULL) { | |
1268 | return; | |
1269 | } | |
1270 | ||
1271 | memset(cssmPcs, 0, sizeof(*cssmPcs)); | |
1272 | } | |
1273 | ||
1274 | ||
1275 | #pragma mark ----- ECDSA_SigAlgParams support ----- | |
1276 | ||
1277 | /* | |
1278 | * Some implementations use a two-OID mechanism to specify ECDSA signature | |
1279 | * algorithm with a digest of other than SHA1. This is really not necessary; | |
1280 | * we use the single-OID method (e.g. CSSMOID_ECDSA_WithSHA512) when | |
1281 | * encoding, but we have to accomodate externally generated items with | |
1282 | * the two-OID method. This routine decodes the digest OID and infers a | |
1283 | * CSSM_ALGORITHMS from it. | |
1284 | * Throws CSSMERR_CL_UNKNOWN_FORMAT on any error. | |
1285 | */ | |
1286 | CSSM_ALGORITHMS CL_nssDecodeECDSASigAlgParams( | |
1287 | const CSSM_DATA &encParams, | |
1288 | SecNssCoder &coder) | |
1289 | { | |
1290 | CSSM_X509_ALGORITHM_IDENTIFIER algParams; | |
1291 | memset(&algParams, 0, sizeof(algParams)); | |
1292 | PRErrorCode prtn = coder.decodeItem(encParams, kSecAsn1AlgorithmIDTemplate, &algParams); | |
1293 | if(prtn) { | |
1294 | clErrorLog("CL_nssDecodeECDSASigAlgParams: error decoding CSSM_X509_ALGORITHM_IDENTIFIER\n"); | |
1295 | CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); | |
1296 | } | |
1297 | ||
1298 | /* get the digest algorithm, convert to ECDSA w/digest OID */ | |
1299 | CSSM_ALGORITHMS digestAlg = CL_oidToAlg(algParams.algorithm); | |
1300 | switch(digestAlg) { | |
1301 | case CSSM_ALGID_SHA1: | |
1302 | return CSSM_ALGID_SHA1WithECDSA; | |
1303 | case CSSM_ALGID_SHA224: | |
1304 | return CSSM_ALGID_SHA224WithECDSA; | |
1305 | case CSSM_ALGID_SHA256: | |
1306 | return CSSM_ALGID_SHA256WithECDSA; | |
1307 | case CSSM_ALGID_SHA384: | |
1308 | return CSSM_ALGID_SHA384WithECDSA; | |
1309 | case CSSM_ALGID_SHA512: | |
1310 | return CSSM_ALGID_SHA512WithECDSA; | |
1311 | default: | |
1312 | clErrorLog("CL_nssDecodeECDSASigAlgParams: unknown digest algorithm\n"); | |
1313 | CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); | |
1314 | } | |
1315 | } | |
1316 | ||
1317 | #pragma mark ----- Top-level Cert/CRL encode and decode ----- | |
1318 | ||
1319 | /* | |
1320 | * To ensure a secure means of signing and verifying TBSCert blobs, we | |
1321 | * provide these functions to encode and decode just the top-level | |
1322 | * elements of a certificate. Unfortunately there is no guarantee | |
1323 | * that when you decode and re-encode a TBSCert blob, you get the | |
1324 | * same thing you started with (although with DER rules, as opposed | |
1325 | * to BER rules, you should). Thus when signing, we sign the TBSCert | |
1326 | * and encode the signed cert here without ever decoding the TBSCert (or, | |
1327 | * at least, without using the decoded version to get the encoded TBS blob). | |
1328 | */ | |
1329 | ||
1330 | void CL_certCrlDecodeComponents( | |
1331 | const CssmData &signedItem, // DER-encoded cert or CRL | |
1332 | CssmOwnedData &tbsBlob, // still DER-encoded | |
1333 | CssmOwnedData &algId, // ditto | |
1334 | CssmOwnedData &rawSig) // raw bits (not an encoded AsnBits) | |
1335 | { | |
1336 | /* BER-decode into temp memory */ | |
1337 | NSS_SignedCertOrCRL nssObj; | |
1338 | SecNssCoder coder; | |
1339 | PRErrorCode prtn; | |
1340 | ||
1341 | memset(&nssObj, 0, sizeof(nssObj)); | |
1342 | prtn = coder.decode(signedItem.data(), signedItem.length(), | |
1343 | kSecAsn1SignedCertOrCRLTemplate, &nssObj); | |
1344 | if(prtn) { | |
1345 | CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); | |
1346 | } | |
1347 | ||
1348 | /* tbsBlob and algId are raw ASN_ANY including tags, which we pass | |
1349 | * back to caller intact */ | |
1350 | tbsBlob.copy(nssObj.tbsBlob.Data, nssObj.tbsBlob.Length); | |
1351 | algId.copy(nssObj.signatureAlgorithm.Data, | |
1352 | nssObj.signatureAlgorithm.Length); | |
1353 | ||
1354 | /* signature is a bit string which we do in fact decode */ | |
1355 | rawSig.copy(nssObj.signature.Data, | |
1356 | (nssObj.signature.Length + 7) / 8); | |
1357 | } | |
1358 | ||
1359 | ||
1360 | /* | |
1361 | * Given pre-DER-encoded blobs, do the final encode step for a signed cert. | |
1362 | */ | |
1363 | void | |
1364 | CL_certEncodeComponents( | |
1365 | const CssmData &TBSCert, // DER-encoded | |
1366 | const CssmData &algId, // ditto | |
1367 | const CssmData &rawSig, // raw bits, not encoded | |
1368 | CssmOwnedData &signedCert) // DER-encoded | |
1369 | { | |
1370 | NSS_SignedCertOrCRL nssObj; | |
1371 | nssObj.tbsBlob.Data = TBSCert.Data; | |
1372 | nssObj.tbsBlob.Length = TBSCert.Length; | |
1373 | nssObj.signatureAlgorithm.Data = algId.Data; | |
1374 | nssObj.signatureAlgorithm.Length = algId.Length; | |
1375 | nssObj.signature.Data = rawSig.Data; | |
1376 | nssObj.signature.Length = rawSig.Length * 8; // BIT STRING | |
1377 | ||
1378 | PRErrorCode prtn; | |
1379 | ||
1380 | prtn = SecNssEncodeItemOdata(&nssObj, | |
1381 | kSecAsn1SignedCertOrCRLTemplate,signedCert); | |
1382 | if(prtn) { | |
1383 | CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR); | |
1384 | } | |
1385 | ||
1386 | } |