2 * Copyright (c) 2003,2011-2012,2014 Apple 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 <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>
35 #pragma mark ----- ArenaAllocator -----
38 * Avoid inlining this for debuggability
40 void *ArenaAllocator::malloc(size_t len
)
43 return mCoder
.malloc(len
);
46 throw std::bad_alloc();
50 /* intentionally not implemented, should never be called */
51 void ArenaAllocator::free(void *p
) _NOEXCEPT
55 void *ArenaAllocator::realloc(void *p
, size_t len
)
57 throw std::bad_alloc();
60 #pragma mark ----- Malloc/Copy/Compare CSSM_DATA -----
63 * Misc. alloc/copy with arbitrary Allocator
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 size_t len
= cdata
.Length
;
125 if(len
> sizeof(uint32
)) {
128 len
= sizeof(uint32
);
131 CssmError::throwMe(toThrow
);
136 uint8
*cp
= cdata
.Data
;
137 for(size_t i
=0; i
<len
; i
++) {
138 rtn
= (rtn
<< 8) | *cp
++;
153 else if(num
< 0x10000) {
156 else if(num
< 0x1000000) {
162 clAllocData(alloc
, cdata
, len
);
163 uint8
*cp
= &cdata
.Data
[len
- 1];
164 for(unsigned i
=0; i
<len
; i
++) {
170 #pragma mark ----- CSSM_BOOL <--> CSSM_DATA -----
172 * A Bool is encoded as one byte of either 0 or 0xff
173 * Default of NSS boolean not present is false
175 CSSM_BOOL
clNssBoolToCssm(
176 const CSSM_DATA
&nssBool
)
178 if((nssBool
.Data
!= NULL
) && (nssBool
.Data
[0] == 0xff)) {
186 void clCssmBoolToNss(
191 uint32 num
= cBool
? 0xff : 0;
192 clIntToData(num
, nssBool
, alloc
);
195 #pragma mark ----- Bit String manipulation -----
198 * Adjust the length of a CSSM_DATA representing a pre-encoded
199 * bit string. On entry the length field is the number of bytes
200 * of data; en exit, the number if bits. Trailing zero bits
201 * are counted as unused (which is how KeyUsage and NetscapeCertType
202 * extensions are encoded).
204 void clCssmBitStringToNss(
207 size_t numBits
= b
.Length
* 8;
209 /* start at end of bit array, scanning backwards looking
210 * for the first set bit */
211 bool foundSet
= false;
212 for(ptrdiff_t dex
=b
.Length
-1; dex
>=0; dex
--) {
213 unsigned bitMask
= 0x01;
214 uint8 byte
= b
.Data
[dex
];
215 for(unsigned bdex
=0; bdex
<8; bdex
++) {
229 /* !foundSet --> numBits = 0 */
230 assert(((numBits
> 0) & foundSet
) || ((numBits
== 0) && !foundSet
));
235 * On entry, Length is bit count; on exit, a byte count.
236 * The job here is to ensure that bits marked as "unused" in the
237 * BER encoding are cleared. Encoding rules say they are undefined in
238 * the actual encoding.
240 void clNssBitStringToCssm(
243 CSSM_SIZE byteCount
= (b
.Length
+ 7) / 8;
244 unsigned partialBits
= b
.Length
& 0x7;
245 b
.Length
= byteCount
;
246 if(partialBits
== 0) {
250 /* mask off unused bits */
251 unsigned unusedBits
= 8 - partialBits
;
252 uint8
*bp
= b
.Data
+ b
.Length
- 1;
253 /* mask = (2 ** unusedBits) - 1 */
254 unsigned mask
= (1 << unusedBits
) - 1;
258 #pragma mark ----- NSS array manipulation -----
260 * How many items in a NULL-terminated array of pointers?
262 unsigned clNssArraySize(
274 /* malloc a NULL-ed array of pointers of size num+1 */
275 void **clNssNullArray(
279 unsigned len
= (num
+ 1) * sizeof(void *);
280 void **p
= (void **)coder
.malloc(len
);
286 * GIven a CSSM_DATA containing a decoded BIT_STRING,
287 * convert to a KeyUsage.
289 CE_KeyUsage
clBitStringToKeyUsage(
290 const CSSM_DATA
&cdata
)
292 size_t toCopy
= (cdata
.Length
+ 7) / 8;
294 /* I hope I never see this... */
295 clErrorLog("clBitStringToKeyUsage: KeyUsage larger than 2 bytes!");
298 unsigned char bits
[2] = {0, 0};
299 memmove(bits
, cdata
.Data
, toCopy
);
300 CE_KeyUsage usage
= (((unsigned)bits
[0]) << 8) | bits
[1];
304 CSSM_ALGORITHMS
CL_oidToAlg(
308 bool found
= cssmOidToAlg(&oid
, &alg
);
310 clErrorLog("CL_oidToAlg: unknown alg\n");
311 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
316 #pragma mark ----- copy CSSM_X509_ALGORITHM_IDENTIFIER -----
319 * Copy CSSM_X509_ALGORITHM_IDENTIFIER, same format (NSS and CSSM).
322 const CSSM_X509_ALGORITHM_IDENTIFIER
&srcAlgId
,
323 CSSM_X509_ALGORITHM_IDENTIFIER
&dstAlgId
,
326 clAllocCopyData(alloc
, srcAlgId
.algorithm
, dstAlgId
.algorithm
);
327 clAllocCopyData(alloc
, srcAlgId
.parameters
, dstAlgId
.parameters
);
330 void CL_freeCssmAlgId(
331 CSSM_X509_ALGORITHM_IDENTIFIER
*cdsaObj
, // optional
334 if(cdsaObj
== NULL
) {
337 alloc
.free(cdsaObj
->algorithm
.Data
);
338 alloc
.free(cdsaObj
->parameters
.Data
);
339 memset(cdsaObj
, 0, sizeof(CSSM_X509_ALGORITHM_IDENTIFIER
));
343 #pragma mark ----- CSSM_X509_TIME <--> NSS format -----
346 * Map the tag associated with a choice of DirectoryString elements to
347 * a template array for encoding/decoding that string type.
348 * Contrary to RFC2459, we allow the IA5String type, which is actually
349 * used in the real world (cf. the email address in Thawte's serverbasic
353 /* The template chooser does the work here */
355 bool CL_nssTimeToCssm(
356 const NSS_TaggedItem
&nssTime
,
357 CSSM_X509_TIME
&cssmObj
,
360 cssmObj
.timeType
= nssTime
.tag
;
361 clAllocCopyData(alloc
, nssTime
.item
, cssmObj
.time
);
366 * CSSM time to NSS time.
368 void CL_cssmTimeToNss(
369 const CSSM_X509_TIME
&cssmTime
,
370 NSS_TaggedItem
&nssTime
,
373 nssTime
.tag
= cssmTime
.timeType
;
374 coder
.allocCopyItem(cssmTime
.time
, nssTime
.item
);
377 void CL_freeCssmTime(
378 CSSM_X509_TIME
*cssmTime
,
381 if(cssmTime
== NULL
) {
384 if(cssmTime
->time
.Data
) {
385 alloc
.free(cssmTime
->time
.Data
);
387 memset(cssmTime
, 0, sizeof(CSSM_X509_TIME
));
391 #pragma mark ----- CSSM_X509_SUBJECT_PUBLIC_KEY_INFO <--> CSSM_KEY -----
394 * Copy a CSSM_X509_SUBJECT_PUBLIC_KEY_INFO.
396 * Same format (NSS and CSSM), EXCEPT:
398 * Objects which have just been NSS decoded or are about to be
399 * NSS encoded have the subjectPublicKey.Length field in BITS
400 * since this field is wrapped in a BIT STRING upon encoding.
402 * Caller tells us which format (bits or bytes)
403 * to use for each of {src, dst}.
405 void CL_copySubjPubKeyInfo(
406 const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
&srcInfo
,
408 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
&dstInfo
,
412 CL_copyAlgId(srcInfo
.algorithm
, dstInfo
.algorithm
, alloc
);
414 CSSM_DATA srcKey
= srcInfo
.subjectPublicKey
;
416 srcKey
.Length
= (srcKey
.Length
+ 7) / 8;
418 clAllocCopyData(alloc
, srcKey
, dstInfo
.subjectPublicKey
);
420 dstInfo
.subjectPublicKey
.Length
*= 8;
425 * Obtain a CSSM_KEY from a CSSM_X509_SUBJECT_PUBLIC_KEY_INFO,
426 * inferring as much as we can from required fields
427 * (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO) and extensions (for
428 * KeyUse, obtained from the optional DecodedCert).
430 CSSM_KEY_PTR
CL_extractCSSMKeyNSS(
431 const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
&keyInfo
,
433 const DecodedCert
*decodedCert
) // optional
435 CSSM_KEY_PTR cssmKey
= (CSSM_KEY_PTR
) alloc
.malloc(sizeof(CSSM_KEY
));
436 memset(cssmKey
, 0, sizeof(CSSM_KEY
));
437 CSSM_KEYHEADER
&hdr
= cssmKey
->KeyHeader
;
438 CssmRemoteData
keyData(alloc
, cssmKey
->KeyData
);
440 hdr
.HeaderVersion
= CSSM_KEYHEADER_VERSION
;
442 hdr
.BlobType
= CSSM_KEYBLOB_RAW
;
443 hdr
.AlgorithmId
= CL_oidToAlg(keyInfo
.algorithm
.algorithm
);
444 hdr
.KeyAttr
= CSSM_KEYATTR_MODIFIABLE
| CSSM_KEYATTR_EXTRACTABLE
;
447 * Format inferred from AlgorithmId. I have never seen these defined
448 * anywhere, e.g., what's the format of an RSA public key in a cert?
449 * X509 certainly doesn't say. However. the following two cases are
450 * known to be correct.
452 switch(hdr
.AlgorithmId
) {
454 hdr
.Format
= CSSM_KEYBLOB_RAW_FORMAT_PKCS1
;
457 case CSSM_ALGID_ECDSA
:
459 case CSSM_ALGMODE_PKCS1_EME_OAEP
:
460 hdr
.Format
= CSSM_KEYBLOB_RAW_FORMAT_X509
;
463 /* CSSM_KEYBLOB_RAW_FORMAT_NONE --> DER encoded */
464 hdr
.Format
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
468 hdr
.Format
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
470 hdr
.KeyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
472 /* KeyUsage inferred from extensions */
474 hdr
.KeyUsage
= decodedCert
->inferKeyUsage();
477 hdr
.KeyUsage
= CSSM_KEYUSE_ANY
;
480 /* start/end date unknown, leave zero */
481 hdr
.WrapAlgorithmId
= CSSM_ALGID_NONE
;
482 hdr
.WrapMode
= CSSM_ALGMODE_NONE
;
484 switch(hdr
.AlgorithmId
) {
486 case CSSM_ALGID_ECDSA
:
488 case CSSM_ALGMODE_PKCS1_EME_OAEP
:
491 * Just encode the whole subject public key info blob.
492 * NOTE we're assuming that the keyInfo.subjectPublicKey
493 * field is in the NSS_native BITSTRING format, i.e.,
494 * its Length field is in bits and we don't have to adjust.
496 PRErrorCode prtn
= SecNssEncodeItemOdata(&keyInfo
,
497 kSecAsn1SubjectPublicKeyInfoTemplate
, keyData
);
499 clErrorLog("extractCSSMKey: error on reencode\n");
500 CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR
);
507 * keyInfo.subjectPublicKey (in BITS) ==> KeyData
509 keyData
.copy(keyInfo
.subjectPublicKey
.Data
,
510 (keyInfo
.subjectPublicKey
.Length
+ 7) / 8);
514 * LogicalKeySizeInBits - ask the CSP
516 CSSM_CSP_HANDLE cspHand
= getGlobalCspHand(true);
517 CSSM_KEY_SIZE keySize
;
519 crtn
= CSSM_QueryKeySizeInBits(cspHand
, CSSM_INVALID_HANDLE
, cssmKey
,
523 CssmError::throwMe(crtn
);
524 case CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE
:
526 * This is how the CSP indicates a "partial" public key,
527 * with a valid public key value but no alg-specific
528 * parameters (currently, DSA only).
530 hdr
.KeyAttr
|= CSSM_KEYATTR_PARTIAL
;
533 cssmKey
->KeyHeader
.LogicalKeySizeInBits
=
534 keySize
.LogicalKeySizeInBits
;
543 * Set up a encoded NULL for CSSM_X509_ALGORITHM_IDENTIFIER.parameters.
545 void CL_nullAlgParams(
546 CSSM_X509_ALGORITHM_IDENTIFIER
&algId
)
548 static const uint8 encNull
[2] = { SEC_ASN1_NULL
, 0 };
549 CSSM_DATA encNullData
;
550 encNullData
.Data
= (uint8
*)encNull
;
551 encNullData
.Length
= 2;
553 algId
.parameters
= encNullData
;
557 * Convert a CSSM_KEY to a CSSM_X509_SUBJECT_PUBLIC_KEY_INFO. The
558 * CSSM key must be in raw format and with a specific blob format.
559 * -- RSA keys have to be CSSM_KEYBLOB_RAW_FORMAT_PKCS1
560 * -- DSA keys have to be CSSM_KEYBLOB_RAW_FORMAT_X509
561 * -- ECDSA keys have to be CSSM_KEYBLOB_RAW_FORMAT_X509
563 void CL_CSSMKeyToSubjPubKeyInfoNSS(
564 const CSSM_KEY
&cssmKey
,
565 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
&nssKeyInfo
,
568 const CSSM_KEYHEADER
&hdr
= cssmKey
.KeyHeader
;
569 if(hdr
.BlobType
!= CSSM_KEYBLOB_RAW
) {
570 clErrorLog("CL SetField: must specify RAW key blob\n");
571 CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT
);
573 memset(&nssKeyInfo
, 0, sizeof(nssKeyInfo
));
575 /* algorithm and format dependent from here... */
576 switch(hdr
.AlgorithmId
) {
578 if(hdr
.Format
!= CSSM_KEYBLOB_RAW_FORMAT_PKCS1
) {
579 clErrorLog("CL SetField: RSA key must be in PKCS1 format\n");
580 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT
);
585 /* Key header's algorithm --> OID */
586 const CSSM_OID
*oid
= cssmAlgToOid(hdr
.AlgorithmId
);
588 clErrorLog("CL SetField: Unknown key algorithm\n");
589 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
);
591 CSSM_X509_ALGORITHM_IDENTIFIER
&algId
= nssKeyInfo
.algorithm
;
592 coder
.allocCopyItem(*oid
, algId
.algorithm
);
594 /* NULL algorithm parameters, always in this case */
595 CL_nullAlgParams(algId
);
597 /* Copy key bits, destination is a BIT STRING */
598 coder
.allocCopyItem(cssmKey
.KeyData
, nssKeyInfo
.subjectPublicKey
);
599 nssKeyInfo
.subjectPublicKey
.Length
*= 8;
603 case CSSM_ALGID_ECDSA
:
604 if(hdr
.Format
!= CSSM_KEYBLOB_RAW_FORMAT_X509
) {
605 clErrorLog("CL SetField: DSA/ECDSA key must be in X509 format\n");
606 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT
);
610 * All we do is decode the whole key blob into the
611 * SubjectPublicKeyInfo.
613 if(coder
.decodeItem(cssmKey
.KeyData
,
614 kSecAsn1SubjectPublicKeyInfoTemplate
,
616 clErrorLog("CL SetField: Error decoding DSA public key\n");
617 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT
);
624 CSSM_KEY_PTR cssmKey
,
628 if(cssmKey
== NULL
) {
631 alloc
.free(cssmKey
->KeyData
.Data
);
632 memset(cssmKey
, 0, sizeof(CSSM_KEY
));
638 #pragma mark ----- CE_AuthorityKeyID <--> NSS_AuthorityKeyId -----
640 void CL_cssmAuthorityKeyIdToNss(
641 const CE_AuthorityKeyID
&cdsaObj
,
642 NSS_AuthorityKeyId
&nssObj
,
645 memset(&nssObj
, 0, sizeof(nssObj
));
646 if(cdsaObj
.keyIdentifierPresent
) {
647 nssObj
.keyIdentifier
= (CSSM_DATA_PTR
)coder
.malloc(sizeof(CSSM_DATA
));
648 coder
.allocCopyItem(cdsaObj
.keyIdentifier
, *nssObj
.keyIdentifier
);
650 if(cdsaObj
.generalNamesPresent
) {
651 /* GeneralNames, the hard one */
652 CL_cssmGeneralNamesToNss(*cdsaObj
.generalNames
,
653 nssObj
.genNames
, coder
);
655 if(cdsaObj
.serialNumberPresent
) {
656 coder
.allocCopyItem(cdsaObj
.serialNumber
,nssObj
.serialNumber
);
660 void CL_nssAuthorityKeyIdToCssm(
661 const NSS_AuthorityKeyId
&nssObj
,
662 CE_AuthorityKeyID
&cdsaObj
,
663 SecNssCoder
&coder
, // for temp decoding
666 if(nssObj
.keyIdentifier
!= NULL
) {
667 cdsaObj
.keyIdentifierPresent
= CSSM_TRUE
;
668 clAllocCopyData(alloc
, *nssObj
.keyIdentifier
, cdsaObj
.keyIdentifier
);
670 if(nssObj
.genNames
.names
!= NULL
) {
671 /* GeneralNames, the hard one */
672 cdsaObj
.generalNamesPresent
= CSSM_TRUE
;
673 cdsaObj
.generalNames
=
674 (CE_GeneralNames
*)alloc
.malloc(sizeof(CE_GeneralNames
));
675 CL_nssGeneralNamesToCssm(nssObj
.genNames
,
676 *cdsaObj
.generalNames
,
680 if(nssObj
.serialNumber
.Data
!= NULL
) {
681 cdsaObj
.serialNumberPresent
= CSSM_TRUE
;
682 clAllocCopyData(alloc
, nssObj
.serialNumber
, cdsaObj
.serialNumber
);
686 #pragma mark ----- CE_AuthorityInfoAccess <--> NSS_AuthorityInfoAccess -----
688 void CL_cssmInfoAccessToNss(
689 const CE_AuthorityInfoAccess
&cdsaObj
,
690 NSS_AuthorityInfoAccess
&nssObj
,
693 memset(&nssObj
, 0, sizeof(nssObj
));
694 uint32 numDescs
= cdsaObj
.numAccessDescriptions
;
695 nssObj
.accessDescriptions
= (NSS_AccessDescription
**)clNssNullArray(numDescs
, coder
);
697 for(unsigned dex
=0; dex
<numDescs
; dex
++) {
698 nssObj
.accessDescriptions
[dex
] = coder
.mallocn
<NSS_AccessDescription
>();
699 CE_AccessDescription
*src
= &cdsaObj
.accessDescriptions
[dex
];
700 NSS_AccessDescription
*dst
= nssObj
.accessDescriptions
[dex
];
701 coder
.allocCopyItem(src
->accessMethod
, dst
->accessMethod
);
703 /* Convert general name, then encode it into destination */
704 NSS_GeneralName nssGenName
;
705 CL_cssmGeneralNameToNss(src
->accessLocation
, nssGenName
, coder
);
706 PRErrorCode prtn
= coder
.encodeItem(&nssGenName
, kSecAsn1GeneralNameTemplate
,
707 dst
->encodedAccessLocation
);
709 clErrorLog("CL_cssmInfoAccessToNss: encode error\n");
710 CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR
);
715 void CL_infoAccessToCssm(
716 const NSS_AuthorityInfoAccess
&nssObj
,
717 CE_AuthorityInfoAccess
&cdsaObj
,
718 SecNssCoder
&coder
, // for temp decoding
721 memset(&cdsaObj
, 0, sizeof(cdsaObj
));
722 unsigned numDescs
= clNssArraySize((const void **)nssObj
.accessDescriptions
);
726 cdsaObj
.accessDescriptions
= (CE_AccessDescription
*)alloc
.malloc(
727 numDescs
* sizeof(CE_AccessDescription
));
728 cdsaObj
.numAccessDescriptions
= numDescs
;
729 for(unsigned dex
=0; dex
<numDescs
; dex
++) {
730 CE_AccessDescription
*dst
= &cdsaObj
.accessDescriptions
[dex
];
731 NSS_AccessDescription
*src
= nssObj
.accessDescriptions
[dex
];
732 clAllocCopyData(alloc
, src
->accessMethod
, dst
->accessMethod
);
734 /* decode the general name */
735 NSS_GeneralName nssGenName
;
736 memset(&nssGenName
, 0, sizeof(nssGenName
));
737 PRErrorCode prtn
= coder
.decodeItem(src
->encodedAccessLocation
,
738 kSecAsn1GeneralNameTemplate
, &nssGenName
);
740 clErrorLog("***Error decoding NSS_AuthorityInfoAccess.accessLocation\n");
741 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
744 /* then convert the result to CSSM */
745 CL_nssGeneralNameToCssm(nssGenName
, dst
->accessLocation
, coder
, alloc
);
749 void CL_freeInfoAccess(
750 CE_AuthorityInfoAccess
&cssmInfo
,
753 uint32 numDescs
= cssmInfo
.numAccessDescriptions
;
754 for(unsigned dex
=0; dex
<numDescs
; dex
++) {
755 CE_AccessDescription
*dst
= &cssmInfo
.accessDescriptions
[dex
];
756 alloc
.free(dst
->accessMethod
.Data
);
757 CL_freeCssmGeneralName(dst
->accessLocation
, alloc
);
759 alloc
.free(cssmInfo
.accessDescriptions
);
763 #pragma mark ----- CE_QC_Statements <--> NSS_QC_Statements -----
765 void CL_cssmQualCertStatementsToNss(
766 const CE_QC_Statements
&cdsaObj
,
767 NSS_QC_Statements
&nssObj
,
770 memset(&nssObj
, 0, sizeof(nssObj
));
771 uint32 numQcs
= cdsaObj
.numQCStatements
;
772 nssObj
.qcStatements
=
773 (NSS_QC_Statement
**)clNssNullArray(numQcs
, coder
);
774 for(uint32 dex
=0; dex
<numQcs
; dex
++) {
775 nssObj
.qcStatements
[dex
] = (NSS_QC_Statement
*)
776 coder
.malloc(sizeof(NSS_QC_Statement
));
777 NSS_QC_Statement
*dst
= nssObj
.qcStatements
[dex
];
778 CE_QC_Statement
*src
= &cdsaObj
.qcStatements
[dex
];
779 memset(dst
, 0, sizeof(*dst
));
780 coder
.allocCopyItem(src
->statementId
, dst
->statementId
);
781 if(src
->semanticsInfo
) {
783 /* this is either/or, not both */
784 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
787 /* encode this CE_SemanticsInformation */
788 CE_SemanticsInformation
*srcSI
= src
->semanticsInfo
;
789 NSS_SemanticsInformation dstSI
;
790 memset(&dstSI
, 0, sizeof(dstSI
));
791 if(srcSI
->semanticsIdentifier
) {
792 dstSI
.semanticsIdentifier
= (CSSM_DATA_PTR
)coder
.malloc(sizeof(CSSM_DATA
));
793 coder
.allocCopyItem(*srcSI
->semanticsIdentifier
,
794 *dstSI
.semanticsIdentifier
);
796 if(srcSI
->nameRegistrationAuthorities
) {
797 dstSI
.nameRegistrationAuthorities
=
798 (NSS_GeneralNames
*)coder
.malloc(sizeof(NSS_GeneralNames
));
799 CL_cssmGeneralNamesToNss(*srcSI
->nameRegistrationAuthorities
,
800 *dstSI
.nameRegistrationAuthorities
, coder
);
802 PRErrorCode prtn
= coder
.encodeItem(&dstSI
, kSecAsn1SemanticsInformationTemplate
,
805 clErrorLog("CL_cssmQualCertStatementsToNss: encode error\n");
806 CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR
);
811 /* drop in as ASN_ANY */
812 coder
.allocCopyItem(*src
->otherInfo
, dst
->info
);
817 void CL_qualCertStatementsToCssm(
818 const NSS_QC_Statements
&nssObj
,
819 CE_QC_Statements
&cdsaObj
,
820 SecNssCoder
&coder
, // for temp decoding
823 memset(&cdsaObj
, 0, sizeof(cdsaObj
));
824 unsigned numQcs
= clNssArraySize((const void **)nssObj
.qcStatements
);
828 cdsaObj
.qcStatements
= (CE_QC_Statement
*)alloc
.malloc(
829 numQcs
* sizeof(CE_QC_Statement
));
830 cdsaObj
.numQCStatements
= numQcs
;
831 for(unsigned dex
=0; dex
<numQcs
; dex
++) {
832 CE_QC_Statement
*dst
= &cdsaObj
.qcStatements
[dex
];
833 NSS_QC_Statement
*src
= nssObj
.qcStatements
[dex
];
835 memset(dst
, 0, sizeof(*dst
));
836 clAllocCopyData(alloc
, src
->statementId
, dst
->statementId
);
839 * Whether the optional info is a SemanticsInformation or is uninterpreted
840 * DER data depends on statementId.
843 if(clCompareCssmData(&src
->statementId
, &CSSMOID_OID_QCS_SYNTAX_V2
)) {
844 NSS_SemanticsInformation srcSI
;
845 memset(&srcSI
, 0, sizeof(srcSI
));
847 /* decode info as a NSS_SemanticsInformation */
848 PRErrorCode prtn
= coder
.decodeItem(src
->info
,
849 kSecAsn1SemanticsInformationTemplate
, &srcSI
);
851 clErrorLog("***Error decoding CE_SemanticsInformation\n");
852 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
855 /* NSS_SemanticsInformation --> CE_SemanticsInformation */
857 (CE_SemanticsInformation
*)alloc
.malloc(sizeof(CE_SemanticsInformation
));
858 CE_SemanticsInformation
*dstSI
= dst
->semanticsInfo
;
859 memset(dstSI
, 0, sizeof(*dstSI
));
860 if(srcSI
.semanticsIdentifier
) {
861 dstSI
->semanticsIdentifier
= (CSSM_OID
*)alloc
.malloc(sizeof(CSSM_OID
));
862 clAllocCopyData(alloc
, *srcSI
.semanticsIdentifier
, *dstSI
->semanticsIdentifier
);
864 if(srcSI
.nameRegistrationAuthorities
) {
865 dstSI
->nameRegistrationAuthorities
=
866 (CE_NameRegistrationAuthorities
*)alloc
.malloc(
867 sizeof(CE_NameRegistrationAuthorities
));
868 CL_nssGeneralNamesToCssm(*srcSI
.nameRegistrationAuthorities
,
869 *dstSI
->nameRegistrationAuthorities
,
875 dst
->otherInfo
= (CSSM_DATA_PTR
)alloc
.malloc(sizeof(CSSM_DATA
));
876 clAllocCopyData(alloc
, src
->info
, *dst
->otherInfo
);
882 void CL_freeQualCertStatements(
883 CE_QC_Statements
&cssmQCs
,
886 uint32 numQCs
= cssmQCs
.numQCStatements
;
887 for(unsigned dex
=0; dex
<numQCs
; dex
++) {
888 CE_QC_Statement
*dst
= &cssmQCs
.qcStatements
[dex
];
889 alloc
.free(dst
->statementId
.Data
);
890 if(dst
->semanticsInfo
) {
891 CE_SemanticsInformation
*si
= dst
->semanticsInfo
;
892 if(si
->semanticsIdentifier
) {
893 alloc
.free(si
->semanticsIdentifier
->Data
);
894 alloc
.free(si
->semanticsIdentifier
);
896 if(si
->nameRegistrationAuthorities
) {
897 CL_freeCssmGeneralNames(si
->nameRegistrationAuthorities
, alloc
);
898 alloc
.free(si
->nameRegistrationAuthorities
);
903 alloc
.free(dst
->otherInfo
->Data
);
904 alloc
.free(dst
->otherInfo
);
907 alloc
.free(cssmQCs
.qcStatements
);
910 #pragma mark ----- decode/encode CE_DistributionPointName -----
912 /* This is always a DER-encoded blob at the NSS level */
913 void CL_decodeDistributionPointName(
914 const CSSM_DATA
&nssBlob
,
915 CE_DistributionPointName
&cssmDpn
,
919 memset(&cssmDpn
, 0, sizeof(CE_DistributionPointName
));
920 if(nssBlob
.Length
== 0) {
921 clErrorLog("***CL_decodeDistributionPointName: bad PointName\n");
922 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
924 unsigned char tag
= nssBlob
.Data
[0] & SEC_ASN1_TAGNUM_MASK
;
926 case NSS_DIST_POINT_FULL_NAME_TAG
:
928 /* decode to temp coder memory */
929 NSS_GeneralNames gnames
;
931 if(coder
.decodeItem(nssBlob
, kSecAsn1DistPointFullNameTemplate
,
933 clErrorLog("***Error decoding DistPointFullName\n");
934 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
937 cssmDpn
.nameType
= CE_CDNT_FullName
;
938 cssmDpn
.dpn
.fullName
= (CE_GeneralNames
*)alloc
.malloc(
939 sizeof(CE_GeneralNames
));
941 /* copy out to caller */
942 CL_nssGeneralNamesToCssm(gnames
,
943 *cssmDpn
.dpn
.fullName
, coder
, alloc
);
946 case NSS_DIST_POINT_RDN_TAG
:
948 /* decode to temp coder memory */
950 memset(&rdn
, 0, sizeof(rdn
));
951 if(coder
.decodeItem(nssBlob
, kSecAsn1DistPointRDNTemplate
,
953 clErrorLog("***Error decoding DistPointRDN\n");
954 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
957 cssmDpn
.nameType
= CE_CDNT_NameRelativeToCrlIssuer
;
958 cssmDpn
.dpn
.rdn
= (CSSM_X509_RDN_PTR
)alloc
.malloc(
959 sizeof(CSSM_X509_RDN
));
961 /* copy out to caller */
962 CL_nssRdnToCssm(rdn
, *cssmDpn
.dpn
.rdn
, alloc
, coder
);
966 clErrorLog("***Bad CE_DistributionPointName tag\n");
967 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
971 void CL_encodeDistributionPointName(
972 CE_DistributionPointName
&cpoint
,
976 const SecAsn1Template
*templ
= NULL
;
977 NSS_GeneralNames gnames
;
979 void *encodeSrc
= NULL
;
982 * Our job is to convert one of two incoming aggregate types
983 * into NSS format, then encode the result into npoint.
985 switch(cpoint
.nameType
) {
986 case CE_CDNT_FullName
:
987 CL_cssmGeneralNamesToNss(*cpoint
.dpn
.fullName
,
990 templ
= kSecAsn1DistPointFullNameTemplate
;
993 case CE_CDNT_NameRelativeToCrlIssuer
:
994 CL_cssmRdnToNss(*cpoint
.dpn
.rdn
, rdn
, coder
);
996 templ
= kSecAsn1DistPointRDNTemplate
;
999 clErrorLog("CL_encodeDistributionPointName: bad nameType\n");
1000 CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG
);
1002 if(coder
.encodeItem(encodeSrc
, templ
, npoint
)) {
1003 clErrorLog("CL_encodeDistributionPointName: encode error\n");
1004 CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR
);
1009 #pragma mark --- CE_CRLDistPointsSyntax <--> NSS_CRLDistributionPoints ---
1011 void CL_cssmDistPointsToNss(
1012 const CE_CRLDistPointsSyntax
&cdsaObj
,
1013 NSS_CRLDistributionPoints
&nssObj
,
1016 memset(&nssObj
, 0, sizeof(nssObj
));
1017 unsigned numPoints
= cdsaObj
.numDistPoints
;
1018 if(numPoints
== 0) {
1022 (NSS_DistributionPoint
**)clNssNullArray(numPoints
, coder
);
1023 for(unsigned dex
=0; dex
<numPoints
; dex
++) {
1024 nssObj
.distPoints
[dex
] = (NSS_DistributionPoint
*)
1025 coder
.malloc(sizeof(NSS_DistributionPoint
));
1026 NSS_DistributionPoint
*npoint
= nssObj
.distPoints
[dex
];
1027 memset(npoint
, 0, sizeof(NSS_DistributionPoint
));
1028 CE_CRLDistributionPoint
*cpoint
= &cdsaObj
.distPoints
[dex
];
1030 /* all fields are optional */
1031 if(cpoint
->distPointName
) {
1032 /* encode and drop into ASN_ANY slot */
1033 npoint
->distPointName
= (CSSM_DATA
*)
1034 coder
.malloc(sizeof(CSSM_DATA
));
1035 CL_encodeDistributionPointName(*cpoint
->distPointName
,
1036 *npoint
->distPointName
, coder
);
1040 if(cpoint
->reasonsPresent
) {
1041 /* bit string, presumed max length 8 bits */
1042 coder
.allocItem(npoint
->reasons
, 1);
1043 npoint
->reasons
.Data
[0] = cpoint
->reasons
;
1044 /* adjust for bit string length */
1045 npoint
->reasons
.Length
= 8;
1048 if(cpoint
->crlIssuer
) {
1049 CL_cssmGeneralNamesToNss(*cpoint
->crlIssuer
,
1050 npoint
->crlIssuer
, coder
);
1055 void CL_nssDistPointsToCssm(
1056 const NSS_CRLDistributionPoints
&nssObj
,
1057 CE_CRLDistPointsSyntax
&cdsaObj
,
1058 SecNssCoder
&coder
, // for temp decoding
1061 memset(&cdsaObj
, 0, sizeof(cdsaObj
));
1062 unsigned numPoints
= clNssArraySize((const void **)nssObj
.distPoints
);
1063 if(numPoints
== 0) {
1067 unsigned len
= sizeof(CE_CRLDistributionPoint
) * numPoints
;
1068 cdsaObj
.distPoints
= (CE_CRLDistributionPoint
*)alloc
.malloc(len
);
1069 memset(cdsaObj
.distPoints
, 0, len
);
1070 cdsaObj
.numDistPoints
= numPoints
;
1072 for(unsigned dex
=0; dex
<numPoints
; dex
++) {
1073 CE_CRLDistributionPoint
&cpoint
= cdsaObj
.distPoints
[dex
];
1074 NSS_DistributionPoint
&npoint
= *(nssObj
.distPoints
[dex
]);
1076 /* All three fields are optional */
1077 if(npoint
.distPointName
!= NULL
) {
1078 /* Drop in a CE_DistributionPointName */
1079 CE_DistributionPointName
*cname
=
1080 (CE_DistributionPointName
*)alloc
.malloc(
1081 sizeof(CE_DistributionPointName
));
1082 memset(cname
, 0, sizeof(*cname
));
1083 cpoint
.distPointName
= cname
;
1086 * This one is currently still encoded; we have to peek
1087 * at its tag and decode accordingly.
1089 CL_decodeDistributionPointName(*npoint
.distPointName
,
1090 *cname
, coder
, alloc
);
1093 if(npoint
.reasons
.Data
!= NULL
) {
1094 /* careful, it's a bit string */
1095 if(npoint
.reasons
.Length
> 8) {
1096 clErrorLog("***CL_nssDistPointsToCssm: Malformed reasons\n");
1097 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
1099 cpoint
.reasonsPresent
= CSSM_TRUE
;
1100 if(npoint
.reasons
.Length
!= 0) {
1101 cpoint
.reasons
= npoint
.reasons
.Data
[0];
1105 if(npoint
.crlIssuer
.names
!= NULL
) {
1106 /* Cook up a new CE_GeneralNames */
1108 (CE_GeneralNames
*)alloc
.malloc(sizeof(CE_GeneralNames
));
1109 CL_nssGeneralNamesToCssm(npoint
.crlIssuer
, *cpoint
.crlIssuer
,
1115 #pragma mark ----- IssuingDistributionPoint -----
1117 void CL_nssIssuingDistPointToCssm(
1118 NSS_IssuingDistributionPoint
*nssIdp
,
1119 CE_IssuingDistributionPoint
*cssmIdp
,
1123 /* All fields optional */
1124 memset(cssmIdp
, 0, sizeof(*cssmIdp
));
1125 if(nssIdp
->distPointName
) {
1126 CE_DistributionPointName
*cssmDp
= (CE_DistributionPointName
*)
1127 alloc
.malloc(sizeof(CE_DistributionPointName
));
1130 * This one is currently still encoded; we have to peek
1131 * at its tag and decode accordingly.
1133 CL_decodeDistributionPointName(*nssIdp
->distPointName
,
1134 *cssmDp
, coder
, alloc
);
1135 cssmIdp
->distPointName
= cssmDp
;
1137 if(nssIdp
->onlyUserCerts
) {
1138 cssmIdp
->onlyUserCertsPresent
= CSSM_TRUE
;
1139 cssmIdp
->onlyUserCerts
= clNssBoolToCssm(*nssIdp
->onlyUserCerts
);
1141 if(nssIdp
->onlyCACerts
) {
1142 cssmIdp
->onlyCACertsPresent
= CSSM_TRUE
;
1143 cssmIdp
->onlyCACerts
= clNssBoolToCssm(*nssIdp
->onlyCACerts
);
1145 if(nssIdp
->onlySomeReasons
) {
1146 cssmIdp
->onlySomeReasonsPresent
= CSSM_TRUE
;
1147 if(nssIdp
->onlySomeReasons
->Length
> 0) {
1148 cssmIdp
->onlySomeReasons
= *nssIdp
->onlySomeReasons
->Data
;
1151 cssmIdp
->onlySomeReasons
= 0;
1154 if(nssIdp
->indirectCRL
) {
1155 cssmIdp
->indirectCrlPresent
= CSSM_TRUE
;
1156 cssmIdp
->indirectCrl
= clNssBoolToCssm(*nssIdp
->indirectCRL
);
1160 #pragma mark --- CE_NameConstraints <--> NSS_NameConstraints ---
1162 void CL_cssmNameConstraintsToNss(
1163 const CE_NameConstraints
&cdsaObj
,
1164 NSS_NameConstraints
&nssObj
,
1170 void CL_nssNameConstraintsToCssm(
1171 const NSS_NameConstraints
&nssObj
,
1172 CE_NameConstraints
&cdsaObj
,
1173 SecNssCoder
&coder
, // for temp decoding
1179 void CL_freeCssmNameConstraints(
1180 CE_NameConstraints
*cssmNcs
,
1183 if(cssmNcs
== NULL
) {
1186 //%%%FIXME need to add a CL_freeCssmGeneralSubtrees function to clNameUtils{.h,.cpp}
1188 switch(cssmDpn
->nameType
) {
1189 case CE_CDNT_FullName
:
1190 CL_freeCssmGeneralNames(cssmDpn
->dpn
.fullName
, alloc
);
1191 alloc
.free(cssmDpn
->dpn
.fullName
);
1193 case CE_CDNT_NameRelativeToCrlIssuer
:
1194 CL_freeX509Rdn(cssmDpn
->dpn
.rdn
, alloc
);
1195 alloc
.free(cssmDpn
->dpn
.rdn
);
1199 memset(cssmNcs
, 0, sizeof(*cssmNcs
));
1202 #pragma mark --- CE_PolicyMappings <--> NSS_PolicyMappings ---
1204 void CL_cssmPolicyMappingsToNss(
1205 const CE_PolicyMappings
&cdsaObj
,
1206 NSS_PolicyMappings
&nssObj
,
1212 void CL_nssPolicyMappingsToCssm(
1213 const NSS_PolicyMappings
&nssObj
,
1214 CE_PolicyMappings
&cdsaObj
,
1215 SecNssCoder
&coder
, // for temp decoding
1221 void CL_freeCssmPolicyMappings(
1222 CE_PolicyMappings
*cssmPms
,
1225 if(cssmPms
== NULL
) {
1230 memset(cssmPms
, 0, sizeof(*cssmPms
));
1233 #pragma mark --- CE_PolicyConstraints <--> NSS_PolicyConstraints ---
1235 void CL_cssmPolicyConstraintsToNss(
1236 const CE_PolicyConstraints
*cdsaObj
,
1237 NSS_PolicyConstraints
*nssObj
,
1243 void CL_nssPolicyConstraintsToCssm(
1244 const NSS_PolicyConstraints
*nssObj
,
1245 CE_PolicyConstraints
*cdsaObj
,
1246 SecNssCoder
&coder
, // for temp decoding
1249 memset(cdsaObj
, 0, sizeof(*cdsaObj
));
1250 if(nssObj
->requireExplicitPolicy
.Data
) {
1251 cdsaObj
->requireExplicitPolicyPresent
= CSSM_TRUE
;
1252 cdsaObj
->inhibitPolicyMapping
= clDataToInt(
1253 nssObj
->requireExplicitPolicy
, 0);
1255 if(nssObj
->inhibitPolicyMapping
.Data
) {
1256 cdsaObj
->inhibitPolicyMappingPresent
= CSSM_TRUE
;
1257 cdsaObj
->inhibitPolicyMapping
= clDataToInt(
1258 nssObj
->inhibitPolicyMapping
, 0);
1262 void CL_freeCssmPolicyConstraints(
1263 CE_PolicyConstraints
*cssmPcs
,
1266 if(cssmPcs
== NULL
) {
1270 memset(cssmPcs
, 0, sizeof(*cssmPcs
));
1274 #pragma mark ----- ECDSA_SigAlgParams support -----
1277 * Some implementations use a two-OID mechanism to specify ECDSA signature
1278 * algorithm with a digest of other than SHA1. This is really not necessary;
1279 * we use the single-OID method (e.g. CSSMOID_ECDSA_WithSHA512) when
1280 * encoding, but we have to accomodate externally generated items with
1281 * the two-OID method. This routine decodes the digest OID and infers a
1282 * CSSM_ALGORITHMS from it.
1283 * Throws CSSMERR_CL_UNKNOWN_FORMAT on any error.
1285 CSSM_ALGORITHMS
CL_nssDecodeECDSASigAlgParams(
1286 const CSSM_DATA
&encParams
,
1289 CSSM_X509_ALGORITHM_IDENTIFIER algParams
;
1290 memset(&algParams
, 0, sizeof(algParams
));
1291 PRErrorCode prtn
= coder
.decodeItem(encParams
, kSecAsn1AlgorithmIDTemplate
, &algParams
);
1293 clErrorLog("CL_nssDecodeECDSASigAlgParams: error decoding CSSM_X509_ALGORITHM_IDENTIFIER\n");
1294 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
1297 /* get the digest algorithm, convert to ECDSA w/digest OID */
1298 CSSM_ALGORITHMS digestAlg
= CL_oidToAlg(algParams
.algorithm
);
1300 case CSSM_ALGID_SHA1
:
1301 return CSSM_ALGID_SHA1WithECDSA
;
1302 case CSSM_ALGID_SHA224
:
1303 return CSSM_ALGID_SHA224WithECDSA
;
1304 case CSSM_ALGID_SHA256
:
1305 return CSSM_ALGID_SHA256WithECDSA
;
1306 case CSSM_ALGID_SHA384
:
1307 return CSSM_ALGID_SHA384WithECDSA
;
1308 case CSSM_ALGID_SHA512
:
1309 return CSSM_ALGID_SHA512WithECDSA
;
1311 clErrorLog("CL_nssDecodeECDSASigAlgParams: unknown digest algorithm\n");
1312 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
1316 #pragma mark ----- Top-level Cert/CRL encode and decode -----
1319 * To ensure a secure means of signing and verifying TBSCert blobs, we
1320 * provide these functions to encode and decode just the top-level
1321 * elements of a certificate. Unfortunately there is no guarantee
1322 * that when you decode and re-encode a TBSCert blob, you get the
1323 * same thing you started with (although with DER rules, as opposed
1324 * to BER rules, you should). Thus when signing, we sign the TBSCert
1325 * and encode the signed cert here without ever decoding the TBSCert (or,
1326 * at least, without using the decoded version to get the encoded TBS blob).
1329 void CL_certCrlDecodeComponents(
1330 const CssmData
&signedItem
, // DER-encoded cert or CRL
1331 CssmOwnedData
&tbsBlob
, // still DER-encoded
1332 CssmOwnedData
&algId
, // ditto
1333 CssmOwnedData
&rawSig
) // raw bits (not an encoded AsnBits)
1335 /* BER-decode into temp memory */
1336 NSS_SignedCertOrCRL nssObj
;
1340 memset(&nssObj
, 0, sizeof(nssObj
));
1341 prtn
= coder
.decode(signedItem
.data(), signedItem
.length(),
1342 kSecAsn1SignedCertOrCRLTemplate
, &nssObj
);
1344 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
1347 /* tbsBlob and algId are raw ASN_ANY including tags, which we pass
1348 * back to caller intact */
1349 tbsBlob
.copy(nssObj
.tbsBlob
.Data
, nssObj
.tbsBlob
.Length
);
1350 algId
.copy(nssObj
.signatureAlgorithm
.Data
,
1351 nssObj
.signatureAlgorithm
.Length
);
1353 /* signature is a bit string which we do in fact decode */
1354 rawSig
.copy(nssObj
.signature
.Data
,
1355 (nssObj
.signature
.Length
+ 7) / 8);
1360 * Given pre-DER-encoded blobs, do the final encode step for a signed cert.
1363 CL_certEncodeComponents(
1364 const CssmData
&TBSCert
, // DER-encoded
1365 const CssmData
&algId
, // ditto
1366 const CssmData
&rawSig
, // raw bits, not encoded
1367 CssmOwnedData
&signedCert
) // DER-encoded
1369 NSS_SignedCertOrCRL nssObj
;
1370 nssObj
.tbsBlob
.Data
= TBSCert
.Data
;
1371 nssObj
.tbsBlob
.Length
= TBSCert
.Length
;
1372 nssObj
.signatureAlgorithm
.Data
= algId
.Data
;
1373 nssObj
.signatureAlgorithm
.Length
= algId
.Length
;
1374 nssObj
.signature
.Data
= rawSig
.Data
;
1375 nssObj
.signature
.Length
= rawSig
.Length
* 8; // BIT STRING
1379 prtn
= SecNssEncodeItemOdata(&nssObj
,
1380 kSecAsn1SignedCertOrCRLTemplate
,signedCert
);
1382 CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR
);