2 * Copyright (c) 2003 Apple Computer, Inc. All Rights Reserved.
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
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.
19 * clNssUtils.cpp - support for libnssasn1-based ASN1 encode/decode
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>
34 #pragma mark ----- ArenaAllocator -----
37 * Avoid inlining this for debuggability
39 void *ArenaAllocator::malloc(size_t len
) throw(std::bad_alloc
)
42 return mCoder
.malloc(len
);
45 throw std::bad_alloc();
49 /* intentionally not implemented, should never be called */
50 void ArenaAllocator::free(void *p
) throw()
52 throw std::bad_alloc();
55 void *ArenaAllocator::realloc(void *p
, size_t len
) throw(std::bad_alloc
)
57 throw std::bad_alloc();
60 #pragma mark ----- Malloc/Copy/Compare CSSM_DATA -----
63 * Misc. alloc/copy with arbitrary CssmAllocator
65 /* malloc d.Data, set d.Length */
75 dst
.Data
= (uint8
*)alloc
.malloc(len
);
86 clAllocData(alloc
, dst
, src
.Length
);
88 memmove(dst
.Data
, src
.Data
, src
.Length
);
93 * Compare two CSSM_DATAs (or two CSSM_OIDs), return true if identical.
95 bool clCompareCssmData(
96 const CSSM_DATA
*data1
,
97 const CSSM_DATA
*data2
)
99 if((data1
== NULL
) || (data1
->Data
== NULL
) ||
100 (data2
== NULL
) || (data2
->Data
== NULL
) ||
101 (data1
->Length
!= data2
->Length
)) {
104 if(data1
->Length
!= data2
->Length
) {
107 if(memcmp(data1
->Data
, data2
->Data
, data1
->Length
) == 0) {
115 #pragma mark ----- CSSM_DATA <--> uint32 -----
118 const CSSM_DATA
&cdata
,
119 CSSM_RETURN toThrow
) /* = CSSMERR_CL_INVALID_CERT_POINTER */
121 if((cdata
.Length
== 0) || (cdata
.Data
== NULL
)) {
124 uint32 len
= cdata
.Length
;
125 if(len
> sizeof(uint32
)) {
126 CssmError::throwMe(toThrow
);
130 uint8
*cp
= cdata
.Data
;
131 for(uint32 i
=0; i
<len
; i
++) {
132 rtn
= (rtn
<< 8) | *cp
++;
140 CssmAllocator
&alloc
)
147 else if(num
< 0x10000) {
150 else if(num
< 0x1000000) {
156 clAllocData(alloc
, cdata
, len
);
157 uint8
*cp
= &cdata
.Data
[len
- 1];
158 for(unsigned i
=0; i
<len
; i
++) {
164 #pragma mark ----- CSSM_BOOL <--> CSSM_DATA -----
166 * A Bool is encoded as one byte of either 0 or 0xff
167 * Default of NSS boolean not present is false
169 CSSM_BOOL
clNssBoolToCssm(
170 const CSSM_DATA
&nssBool
)
172 if((nssBool
.Data
!= NULL
) && (nssBool
.Data
[0] == 0xff)) {
180 void clCssmBoolToNss(
183 CssmAllocator
&alloc
)
185 uint32 num
= cBool
? 0xff : 0;
186 clIntToData(num
, nssBool
, alloc
);
189 #pragma mark ----- Bit String manipulation -----
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).
198 void clCssmBitStringToNss(
201 int numBits
= b
.Length
* 8;
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
++) {
223 /* !foundSet --> numBits = 0 */
224 assert(((numBits
> 0) & foundSet
) || ((numBits
== 0) && !foundSet
));
225 b
.Length
= (uint32
)numBits
;
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.
234 void clNssBitStringToCssm(
237 uint32 byteCount
= (b
.Length
+ 7) / 8;
238 unsigned partialBits
= b
.Length
& 0x7;
239 b
.Length
= byteCount
;
240 if(partialBits
== 0) {
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;
252 #pragma mark ----- NSS array manipulation -----
254 * How many items in a NULL-terminated array of pointers?
256 unsigned clNssArraySize(
268 /* malloc a NULL-ed array of pointers of size num+1 */
269 void **clNssNullArray(
273 unsigned len
= (num
+ 1) * sizeof(void *);
274 void **p
= (void **)coder
.malloc(len
);
280 * GIven a CSSM_DATA containing a decoded BIT_STRING,
281 * convert to a KeyUsage.
283 CE_KeyUsage
clBitStringToKeyUsage(
284 const CSSM_DATA
&cdata
)
286 unsigned toCopy
= (cdata
.Length
+ 7) / 8;
288 /* I hope I never see this... */
289 clErrorLog("clBitStringToKeyUsage: KeyUsage larger than 2 bytes!");
292 unsigned char bits
[2] = {0, 0};
293 memmove(bits
, cdata
.Data
, toCopy
);
294 CE_KeyUsage usage
= (((unsigned)bits
[0]) << 8) | bits
[1];
298 CSSM_ALGORITHMS
CL_oidToAlg(
302 bool found
= cssmOidToAlg(&oid
, &alg
);
304 clErrorLog("CL_oidToAlg: unknown alg\n");
305 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
310 #pragma mark ----- copy CSSM_X509_ALGORITHM_IDENTIFIER -----
313 * Copy CSSM_X509_ALGORITHM_IDENTIFIER, same format (NSS and CSSM).
316 const CSSM_X509_ALGORITHM_IDENTIFIER
&srcAlgId
,
317 CSSM_X509_ALGORITHM_IDENTIFIER
&dstAlgId
,
318 CssmAllocator
&alloc
)
320 clAllocCopyData(alloc
, srcAlgId
.algorithm
, dstAlgId
.algorithm
);
321 clAllocCopyData(alloc
, srcAlgId
.parameters
, dstAlgId
.parameters
);
324 void CL_freeCssmAlgId(
325 CSSM_X509_ALGORITHM_IDENTIFIER
*cdsaObj
, // optional
326 CssmAllocator
&alloc
)
328 if(cdsaObj
== NULL
) {
331 alloc
.free(cdsaObj
->algorithm
.Data
);
332 alloc
.free(cdsaObj
->parameters
.Data
);
333 memset(cdsaObj
, 0, sizeof(CSSM_X509_ALGORITHM_IDENTIFIER
));
337 #pragma mark ----- CSSM_X509_TIME <--> NSS format -----
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
347 /* The template chooser does the work here */
349 bool CL_nssTimeToCssm(
350 const NSS_TaggedItem
&nssTime
,
351 CSSM_X509_TIME
&cssmObj
,
352 CssmAllocator
&alloc
)
354 cssmObj
.timeType
= nssTime
.tag
;
355 clAllocCopyData(alloc
, nssTime
.item
, cssmObj
.time
);
360 * CSSM time to NSS time.
362 void CL_cssmTimeToNss(
363 const CSSM_X509_TIME
&cssmTime
,
364 NSS_TaggedItem
&nssTime
,
367 nssTime
.tag
= cssmTime
.timeType
;
368 coder
.allocCopyItem(cssmTime
.time
, nssTime
.item
);
371 void CL_freeCssmTime(
372 CSSM_X509_TIME
*cssmTime
,
373 CssmAllocator
&alloc
)
375 if(cssmTime
== NULL
) {
378 if(cssmTime
->time
.Data
) {
379 alloc
.free(cssmTime
->time
.Data
);
381 memset(cssmTime
, 0, sizeof(CSSM_X509_TIME
));
385 #pragma mark ----- CSSM_X509_SUBJECT_PUBLIC_KEY_INFO <--> CSSM_KEY -----
388 * Copy a CSSM_X509_SUBJECT_PUBLIC_KEY_INFO.
390 * Same format (NSS and CSSM), EXCEPT:
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.
396 * Caller tells us which format (bits or bytes)
397 * to use for each of {src, dst}.
399 void CL_copySubjPubKeyInfo(
400 const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
&srcInfo
,
402 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
&dstInfo
,
404 CssmAllocator
&alloc
)
406 CL_copyAlgId(srcInfo
.algorithm
, dstInfo
.algorithm
, alloc
);
408 CSSM_DATA srcKey
= srcInfo
.subjectPublicKey
;
410 srcKey
.Length
= (srcKey
.Length
+ 7) / 8;
412 clAllocCopyData(alloc
, srcKey
, dstInfo
.subjectPublicKey
);
414 dstInfo
.subjectPublicKey
.Length
*= 8;
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).
424 CSSM_KEY_PTR
CL_extractCSSMKeyNSS(
425 const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
&keyInfo
,
426 CssmAllocator
&alloc
,
427 const DecodedCert
*decodedCert
) // optional
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
);
434 hdr
.HeaderVersion
= CSSM_KEYHEADER_VERSION
;
436 hdr
.BlobType
= CSSM_KEYBLOB_RAW
;
437 hdr
.AlgorithmId
= CL_oidToAlg(keyInfo
.algorithm
.algorithm
);
438 hdr
.KeyAttr
= CSSM_KEYATTR_MODIFIABLE
| CSSM_KEYATTR_EXTRACTABLE
;
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.
446 switch(hdr
.AlgorithmId
) {
448 hdr
.Format
= CSSM_KEYBLOB_RAW_FORMAT_PKCS1
;
452 hdr
.Format
= CSSM_KEYBLOB_RAW_FORMAT_X509
;
455 /* CSSM_KEYBLOB_RAW_FORMAT_NONE --> DER encoded */
456 hdr
.Format
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
460 hdr
.Format
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
462 hdr
.KeyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
464 /* KeyUsage inferred from extensions */
466 hdr
.KeyUsage
= decodedCert
->inferKeyUsage();
469 hdr
.KeyUsage
= CSSM_KEYUSE_ANY
;
472 /* start/end date unknown, leave zero */
473 hdr
.WrapAlgorithmId
= CSSM_ALGID_NONE
;
474 hdr
.WrapMode
= CSSM_ALGMODE_NONE
;
476 switch(hdr
.AlgorithmId
) {
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.
486 PRErrorCode prtn
= SecNssEncodeItemOdata(&keyInfo
,
487 NSS_SubjectPublicKeyInfoTemplate
, keyData
);
489 clErrorLog("extractCSSMKey: error on reencode\n");
490 CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR
);
497 * keyInfo.subjectPublicKey (in BITS) ==> KeyData
499 keyData
.copy(keyInfo
.subjectPublicKey
.Data
,
500 (keyInfo
.subjectPublicKey
.Length
+ 7) / 8);
505 * LogicalKeySizeInBits - ask the CSP
507 CSSM_CSP_HANDLE cspHand
= getGlobalCspHand(true);
508 CSSM_KEY_SIZE keySize
;
510 crtn
= CSSM_QueryKeySizeInBits(cspHand
, CSSM_INVALID_HANDLE
, cssmKey
,
514 CssmError::throwMe(crtn
);
515 case CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE
:
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).
521 hdr
.KeyAttr
|= CSSM_KEYATTR_PARTIAL
;
524 cssmKey
->KeyHeader
.LogicalKeySizeInBits
=
525 keySize
.LogicalKeySizeInBits
;
537 * Set up a encoded NULL for CSSM_X509_ALGORITHM_IDENTIFIER.parameters.
539 void CL_nullAlgParams(
540 CSSM_X509_ALGORITHM_IDENTIFIER
&algId
)
542 static const uint8 encNull
[2] = { SEC_ASN1_NULL
, 0 };
543 CSSM_DATA encNullData
;
544 encNullData
.Data
= (uint8
*)encNull
;
545 encNullData
.Length
= 2;
547 algId
.parameters
= encNullData
;
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
556 void CL_CSSMKeyToSubjPubKeyInfoNSS(
557 const CSSM_KEY
&cssmKey
,
558 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
&nssKeyInfo
,
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
);
566 memset(&nssKeyInfo
, 0, sizeof(nssKeyInfo
));
568 /* algorithm and format dependent from here... */
569 switch(hdr
.AlgorithmId
) {
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
);
578 /* Key header's algorithm --> OID */
579 const CSSM_OID
*oid
= cssmAlgToOid(hdr
.AlgorithmId
);
581 clErrorLog("CL SetField: Unknown key algorithm\n");
582 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
);
584 CSSM_X509_ALGORITHM_IDENTIFIER
&algId
= nssKeyInfo
.algorithm
;
585 coder
.allocCopyItem(*oid
, algId
.algorithm
);
587 /* NULL algorithm parameters, always in this case */
588 CL_nullAlgParams(algId
);
590 /* Copy key bits, destination is a BIT STRING */
591 coder
.allocCopyItem(cssmKey
.KeyData
, nssKeyInfo
.subjectPublicKey
);
592 nssKeyInfo
.subjectPublicKey
.Length
*= 8;
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
);
602 * All we do is decode the whole key blob into the
603 * SubjectPublicKeyInfo.
605 if(coder
.decodeItem(cssmKey
.KeyData
,
606 NSS_SubjectPublicKeyInfoTemplate
,
608 clErrorLog("CL SetField: Error decoding DSA public key\n");
609 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT
);
616 CSSM_KEY_PTR cssmKey
,
617 CssmAllocator
&alloc
,
620 if(cssmKey
== NULL
) {
623 alloc
.free(cssmKey
->KeyData
.Data
);
624 memset(cssmKey
, 0, sizeof(CSSM_KEY
));
630 #pragma mark ----- CE_AuthorityKeyID <--> NSS_AuthorityKeyId -----
632 void CL_cssmAuthorityKeyIdToNss(
633 const CE_AuthorityKeyID
&cdsaObj
,
634 NSS_AuthorityKeyId
&nssObj
,
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
);
642 if(cdsaObj
.generalNamesPresent
) {
643 /* GeneralNames, the hard one */
644 CL_cssmGeneralNamesToNss(*cdsaObj
.generalNames
,
645 nssObj
.genNames
, coder
);
647 if(cdsaObj
.serialNumberPresent
) {
648 coder
.allocCopyItem(cdsaObj
.serialNumber
,nssObj
.serialNumber
);
652 void CL_nssAuthorityKeyIdToCssm(
653 const NSS_AuthorityKeyId
&nssObj
,
654 CE_AuthorityKeyID
&cdsaObj
,
655 SecNssCoder
&coder
, // for temp decoding
656 CssmAllocator
&alloc
)
658 if(nssObj
.keyIdentifier
!= NULL
) {
659 cdsaObj
.keyIdentifierPresent
= CSSM_TRUE
;
660 clAllocCopyData(alloc
, *nssObj
.keyIdentifier
, cdsaObj
.keyIdentifier
);
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
,
672 if(nssObj
.serialNumber
.Data
!= NULL
) {
673 cdsaObj
.serialNumberPresent
= CSSM_TRUE
;
674 clAllocCopyData(alloc
, nssObj
.serialNumber
, cdsaObj
.serialNumber
);
678 #pragma mark ----- decode/encode CE_DistributionPointName -----
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
,
685 CssmAllocator
&alloc
)
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
);
692 unsigned char tag
= nssBlob
.Data
[0] & SEC_ASN1_TAGNUM_MASK
;
694 case NSS_DIST_POINT_FULL_NAME_TAG
:
696 /* decode to temp coder memory */
697 NSS_GeneralNames gnames
;
699 if(coder
.decodeItem(nssBlob
, NSS_DistPointFullNameTemplate
,
701 clErrorLog("***Error decoding DistPointFullName\n");
702 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
705 cssmDpn
.nameType
= CE_CDNT_FullName
;
706 cssmDpn
.fullName
= (CE_GeneralNames
*)alloc
.malloc(
707 sizeof(CE_GeneralNames
));
709 /* copy out to caller */
710 CL_nssGeneralNamesToCssm(gnames
,
711 *cssmDpn
.fullName
, coder
, alloc
);
714 case NSS_DIST_POINT_RDN_TAG
:
716 /* decode to temp coder memory */
718 memset(&rdn
, 0, sizeof(rdn
));
719 if(coder
.decodeItem(nssBlob
, NSS_DistPointRDNTemplate
,
721 clErrorLog("***Error decoding DistPointRDN\n");
722 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
725 cssmDpn
.nameType
= CE_CDNT_NameRelativeToCrlIssuer
;
726 cssmDpn
.rdn
= (CSSM_X509_RDN_PTR
)alloc
.malloc(
727 sizeof(CSSM_X509_RDN
));
729 /* copy out to caller */
730 CL_nssRdnToCssm(rdn
, *cssmDpn
.rdn
, alloc
, coder
);
734 clErrorLog("***Bad CE_DistributionPointName tag\n");
735 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
739 void CL_encodeDistributionPointName(
740 CE_DistributionPointName
&cpoint
,
744 const SEC_ASN1Template
*templ
= NULL
;
745 NSS_GeneralNames gnames
;
747 void *encodeSrc
= NULL
;
750 * Our job is to convert one of two incoming aggregate types
751 * into NSS format, then encode the result into npoint.
753 switch(cpoint
.nameType
) {
754 case CE_CDNT_FullName
:
755 CL_cssmGeneralNamesToNss(*cpoint
.fullName
,
758 templ
= NSS_DistPointFullNameTemplate
;
761 case CE_CDNT_NameRelativeToCrlIssuer
:
762 CL_cssmRdnToNss(*cpoint
.rdn
, rdn
, coder
);
764 templ
= NSS_DistPointRDNTemplate
;
767 clErrorLog("CL_encodeDistributionPointName: bad nameType\n");
768 CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG
);
770 if(coder
.encodeItem(encodeSrc
, templ
, npoint
)) {
771 clErrorLog("CL_encodeDistributionPointName: encode error\n");
772 CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR
);
777 #pragma mark --- CE_CRLDistPointsSyntax <--> NSS_CRLDistributionPoints ---
779 void CL_cssmDistPointsToNss(
780 const CE_CRLDistPointsSyntax
&cdsaObj
,
781 NSS_CRLDistributionPoints
&nssObj
,
784 memset(&nssObj
, 0, sizeof(nssObj
));
785 unsigned numPoints
= cdsaObj
.numDistPoints
;
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
];
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
);
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;
816 if(cpoint
->crlIssuer
) {
817 CL_cssmGeneralNamesToNss(*cpoint
->crlIssuer
,
818 npoint
->crlIssuer
, coder
);
823 void CL_nssDistPointsToCssm(
824 const NSS_CRLDistributionPoints
&nssObj
,
825 CE_CRLDistPointsSyntax
&cdsaObj
,
826 SecNssCoder
&coder
, // for temp decoding
827 CssmAllocator
&alloc
)
829 memset(&cdsaObj
, 0, sizeof(cdsaObj
));
830 unsigned numPoints
= clNssArraySize((const void **)nssObj
.distPoints
);
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
;
840 for(unsigned dex
=0; dex
<numPoints
; dex
++) {
841 CE_CRLDistributionPoint
&cpoint
= cdsaObj
.distPoints
[dex
];
842 NSS_DistributionPoint
&npoint
= *(nssObj
.distPoints
[dex
]);
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
;
854 * This one is currently still encoded; we have to peek
855 * at its tag and decode accordingly.
857 CL_decodeDistributionPointName(*npoint
.distPointName
,
858 *cname
, coder
, alloc
);
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
);
867 cpoint
.reasonsPresent
= CSSM_TRUE
;
868 if(npoint
.reasons
.Length
!= 0) {
869 cpoint
.reasons
= npoint
.reasons
.Data
[0];
873 if(npoint
.crlIssuer
.names
!= NULL
) {
874 /* Cook up a new CE_GeneralNames */
876 (CE_GeneralNames
*)alloc
.malloc(sizeof(CE_GeneralNames
));
877 CL_nssGeneralNamesToCssm(npoint
.crlIssuer
, *cpoint
.crlIssuer
,
883 #pragma mark ----- IssuingDistributionPoint -----
885 void CL_nssIssuingDistPointToCssm(
886 NSS_IssuingDistributionPoint
*nssIdp
,
887 CE_IssuingDistributionPoint
*cssmIdp
,
889 CssmAllocator
&alloc
)
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
));
898 * This one is currently still encoded; we have to peek
899 * at its tag and decode accordingly.
901 CL_decodeDistributionPointName(*nssIdp
->distPointName
,
902 *cssmDp
, coder
, alloc
);
903 cssmIdp
->distPointName
= cssmDp
;
905 if(nssIdp
->onlyUserCerts
) {
906 cssmIdp
->onlyUserCertsPresent
= CSSM_TRUE
;
907 cssmIdp
->onlyUserCerts
= clNssBoolToCssm(*nssIdp
->onlyUserCerts
);
909 if(nssIdp
->onlyCACerts
) {
910 cssmIdp
->onlyCACertsPresent
= CSSM_TRUE
;
911 cssmIdp
->onlyCACerts
= clNssBoolToCssm(*nssIdp
->onlyCACerts
);
913 if(nssIdp
->onlySomeReasons
) {
914 cssmIdp
->onlySomeReasonsPresent
= CSSM_TRUE
;
915 if(nssIdp
->onlySomeReasons
->Length
> 0) {
916 cssmIdp
->onlySomeReasons
= *nssIdp
->onlySomeReasons
->Data
;
919 cssmIdp
->onlySomeReasons
= 0;
922 if(nssIdp
->indirectCRL
) {
923 cssmIdp
->indirectCrlPresent
= CSSM_TRUE
;
924 cssmIdp
->indirectCrl
= clNssBoolToCssm(*nssIdp
->indirectCRL
);
928 #pragma mark ----- Top-level Cert/CRL encode and decode -----
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).
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)
947 /* BER-decode into temp memory */
948 NSS_SignedCertOrCRL nssObj
;
952 memset(&nssObj
, 0, sizeof(nssObj
));
953 prtn
= coder
.decode(signedItem
.data(), signedItem
.length(),
954 NSS_SignedCertOrCRLTemplate
, &nssObj
);
956 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
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
);
965 /* signature is a bit string which we do in fact decode */
966 rawSig
.copy(nssObj
.signature
.Data
,
967 (nssObj
.signature
.Length
+ 7) / 8);
972 * Given pre-DER-encoded blobs, do the final encode step for a signed cert.
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
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
991 prtn
= SecNssEncodeItemOdata(&nssObj
,
992 NSS_SignedCertOrCRLTemplate
,signedCert
);
994 CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR
);