2 * Copyright (c) 2000-2001 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.
20 * CertSNACC.cpp - snacc-related cert functions
22 * Created 9/1/2000 by Doug Mitchell.
23 * Copyright (c) 2000 by Apple Computer.
26 #include "SnaccUtils.h"
27 #include "CSPAttacher.h"
28 #include "cldebugging.h"
29 #include <Security/pkcs1oids.h>
30 #include <Security/cdsaUtils.h>
31 #include <Security/cssmapple.h>
32 #include <Security/appleoids.h>
33 #include <Security/globalizer.h>
35 #define DEBUG_DECODE 0
37 #define ddprintf(x) printf x
43 * AsnOid "constants" which we construct and cache on demand to avoid the
44 * somewhat expensive op of constructing them every time we test for equality
45 * in CL_snaccOidToCssmAlg.
51 mRsaEncryption(rsaEncryption_arc
),
52 mMd2WithRSAEncryption(md2WithRSAEncryption_arc
),
53 mMd5WithRSAEncryption(md5WithRSAEncryption_arc
),
54 mSha1withRSAEncryption(sha1withRSAEncryption_arc
),
56 mId_dsa_with_sha1(id_dsa_with_sha1_arc
),
57 mAppleFee(appleFee_arc
),
58 mAppleAsc(appleAsc_arc
),
59 mAppleFeeMD5(appleFeeMD5_arc
),
60 mAppleFeeSHA1(appleFeeSHA1_arc
),
61 mAppleFeed(appleFeed_arc
),
62 mAppleFeedExp(appleFeedExp_arc
),
63 mAppleECDSA(appleECDSA_arc
)
66 AsnOid mRsaEncryption
;
67 AsnOid mMd2WithRSAEncryption
;
68 AsnOid mMd5WithRSAEncryption
;
69 AsnOid mSha1withRSAEncryption
;
71 AsnOid mId_dsa_with_sha1
;
81 static ModuleNexus
<AlgOidCache
> algOidCache
;
84 * To ensure a secure means of signing and verifying TBSCert blobs, we
85 * provide these functions to encode and decode just the top-level
86 * elements of a certificate. Snacc doesn't allow you to specify, for
87 * example, a fully encoded TBSCert prior to encoding the whole cert after
88 * signing it - you have to decode the TBSCert, put it and the other
89 * components into a Cert, and then encode the whole thing. Unfortunately
90 * there is no guarantee that when you decode and re-encode a TBSCert blob,
91 * you get the same thing you started with (although with DER rules, as
92 * opposed to BER rules, you should). Thus when signing, we sign the TBSCert
93 * and encode the signed cert here without ever decoding the TBSCert (or,
94 * at least, without using the decoded version to get the encoded TBS blob).
98 CL_certDecodeComponents(
99 const CssmData
&signedCert
, // DER-encoded
100 CssmOwnedData
&TBSCert
, // still DER-encoded
101 CssmOwnedData
&algId
, // ditto
102 CssmOwnedData
&rawSig
) // raw bits (not an encoded AsnBits)
104 CssmAutoData
encodedSig(rawSig
.allocator
);
106 /* drop signedCert into an AsnBuf for processing */
108 buf
.InstallData(reinterpret_cast<char *>(signedCert
.data()), signedCert
.length());
110 /* based on snacc-generated Certificate::BDec() and BDecContent() */
112 AsnLen bytesDecoded
= 0;
113 AsnLen decLen
; // from BDecLen
114 AsnLen totalLen
; // including tag and ASN length
115 char *elemStart
; // ptr to start of element, including tag
119 tag
= BDecTag (buf
, bytesDecoded
, env
);
120 if (tag
!= MAKE_TAG_ID (UNIV
, CONS
, SEQ_TAG_CODE
)) {
121 errorLog1("CL_CertDecodeComponents: bad first-level tag (0x%x)\n", tag
);
122 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
124 decLen
= BDecLen (buf
, bytesDecoded
, env
); // of total
125 /* FIXME - we should be able to ensure right here that we have enough */
127 /* First element, TBSCert */
128 /* Note we need to include the tag and content in the outgoing blobs */
129 elemStart
= buf
.DataPtr() + bytesDecoded
;
130 tag
= BDecTag (buf
, bytesDecoded
, env
);
131 if(tag
!= MAKE_TAG_ID (UNIV
, CONS
, SEQ_TAG_CODE
)) {
132 errorLog1("CL_CertDecodeComponents: bad TBSCert tag (0x%x)\n", tag
);
133 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
136 decLen
= BDecLen (buf
, bytesDecoded
, env
); // DER 'length'
137 /* buf now at first content byte; simulate grabbing content */
138 totalLen
= decLen
+ (bytesDecoded
- (elemStart
- buf
.DataPtr()));
140 bytesDecoded
+= decLen
;
141 TBSCert
.copy(elemStart
, totalLen
);
142 ddprintf(("CL_certDecodeComponents: TBS len %d; data %02x %02x %02x %02x...\n",
143 totalLen
, ((uint8
*)elemStart
)[0], ((uint8
*)elemStart
)[1],
144 ((uint8
*)elemStart
)[2], ((uint8
*)elemStart
)[3]));
146 /* next element, algId */
147 elemStart
= buf
.DataPtr() + bytesDecoded
;
148 tag
= BDecTag (buf
, bytesDecoded
, env
);
149 if(tag
!= MAKE_TAG_ID (UNIV
, CONS
, SEQ_TAG_CODE
)) {
150 errorLog1("CL_CertDecodeComponents: bad AlgId tag (0x%x)\n", tag
);
151 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
153 decLen
= BDecLen (buf
, bytesDecoded
, env
);
154 totalLen
= decLen
+ (bytesDecoded
- (elemStart
- buf
.DataPtr()));
156 bytesDecoded
+= decLen
;
157 algId
.copy(elemStart
, totalLen
);
158 ddprintf(("CL_certDecodeComponents: algId len %d; data %02x %02x %02x...\n",
159 totalLen
, ((uint8
*)elemStart
)[0], ((uint8
*)elemStart
)[1],
160 ((uint8
*)elemStart
)[2]));
162 /* next element, signature */
163 elemStart
= buf
.DataPtr() + bytesDecoded
;
164 tag
= BDecTag (buf
, bytesDecoded
, env
);
165 if((tag
!= MAKE_TAG_ID (UNIV
, CONS
, BITSTRING_TAG_CODE
)) &&
166 (tag
!= MAKE_TAG_ID (UNIV
, PRIM
, BITSTRING_TAG_CODE
))) {
167 errorLog1("CL_CertDecodeComponents: bad sig tag 0x%x\n", tag
);
168 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
170 decLen
= BDecLen (buf
, bytesDecoded
, env
);
171 totalLen
= decLen
+ (bytesDecoded
- (elemStart
- buf
.DataPtr()));
172 encodedSig
.copy(elemStart
, totalLen
);
173 ddprintf(("CL_certDecodeComponents: encodedSig len %d; data %02x %02x "
175 totalLen
, ((uint8
*)elemStart
)[0], ((uint8
*)elemStart
)[1],
176 ((uint8
*)elemStart
)[2], ((uint8
*)elemStart
)[3]));
179 * encodedSig is a DER-encoded AsnBits. Decode for caller.
181 SC_decodeAsnBitsToCssmData(encodedSig
.get(), rawSig
);
182 ddprintf(("CL_certDecodeComponents: rawSig len %d\n", rawSig
.length()));
184 * OK, if we get here, we can skip the remaining stuff from
185 * Certificate::BDecContent(), which involves getting to the end
186 * of indefinte-length data.
190 errorLog0("CL_CertDecodeComponents: throw during decode\n");
194 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
199 * Given pre-DER-encoded blobs, do the final encode step for a signed cert.
202 CL_certEncodeComponents(
203 const CssmData
&TBSCert
, // DER-encoded
204 const CssmData
&algId
, // ditto
205 const CssmData
&rawSig
, // raw bits, not encoded
206 CssmOwnedData
&signedCert
) // DER-encoded
208 /* first BER-encode the signature */
209 AsnBits
snaccSig(reinterpret_cast<char *>(rawSig
.data()),
210 rawSig
.length() * 8);
211 CssmAutoData
encodedSig(signedCert
.allocator
);
212 SC_encodeAsnObj(snaccSig
, encodedSig
, rawSig
.length() + 10);
215 * OK, we have all three cert components already DER-encoded. The encoded
216 * cert is just (tag | contentLength | TBSCert | algId | encodedSig).
217 * To avoid an unneccessary copy at the end of the encode, figure out
218 * the length of tag and contentLength. The tag is known to be one byte.
220 size_t contentLen
= TBSCert
.length() + algId
.length() + encodedSig
.length();
221 size_t lenLen
= SC_lengthOfLength(contentLen
);
222 size_t totalLen
= 1 /* tag */ + lenLen
/* length bytes */ + contentLen
;
223 signedCert
.malloc(totalLen
);
226 char *cp
= (char *)signedCert
.data();
227 *cp
++ = UNIV
| CONS
| SEQ_TAG_CODE
;
230 SC_encodeLength(contentLen
, cp
, lenLen
);
233 /* concatenate the existing components */
234 memcpy(cp
, TBSCert
.data(), TBSCert
.length());
235 cp
+= TBSCert
.length();
236 memcpy(cp
, algId
.data(), algId
.length());
237 cp
+= algId
.length();
238 memcpy(cp
, encodedSig
.data(), encodedSig
.length());
239 CASSERT((cp
+ encodedSig
.length()) ==
240 ((char *)signedCert
.data() + signedCert
.length()));
243 /* malloc/copy a CsmmOid from a snacc-style AsnOid. */
244 void CL_snaccOidToCssm(
247 CssmAllocator
&alloc
)
249 outOid
.Data
= (uint8
*)alloc
.malloc(inOid
.Len());
250 outOid
.Length
= inOid
.Len();
251 const char *cp
= inOid
;
252 memcpy(outOid
.Data
, cp
, outOid
.Length
);
255 /* convert algorithm identifier from CSSM format to snacc format */
256 void CL_cssmAlgIdToSnacc (
257 const CSSM_X509_ALGORITHM_IDENTIFIER
&cssmAlgId
,
258 AlgorithmIdentifier
&snaccAlgId
)
260 snaccAlgId
.algorithm
.Set(reinterpret_cast<char *>(
261 cssmAlgId
.algorithm
.Data
), cssmAlgId
.algorithm
.Length
);
262 if(cssmAlgId
.parameters
.Data
!= NULL
) {
263 /* optional parameters, raw bytes */
264 /* FIXME - is that right? SHould we encode as a bit string?
265 * I've never seen this "ANY" type field used... */
266 snaccAlgId
.parameters
= new AsnAny
;
267 CSM_Buffer
*cbuf
= new CSM_Buffer(
268 reinterpret_cast<char *>(cssmAlgId
.parameters
.Data
),
269 cssmAlgId
.parameters
.Length
);
270 snaccAlgId
.parameters
->value
= cbuf
;
273 CL_nullAlgParams(snaccAlgId
);
277 /* convert algorithm indentifier from snacc format to CSSM format */
278 void CL_snaccAlgIdToCssm (
279 const AlgorithmIdentifier
&snaccAlgId
,
280 CSSM_X509_ALGORITHM_IDENTIFIER
&cssmAlgId
,
281 CssmAllocator
&alloc
)
283 memset(&cssmAlgId
, 0, sizeof(CSSM_X509_ALGORITHM_IDENTIFIER
));
285 /* algorithm - required */
286 CssmOid
&outOid
= CssmOid::overlay(cssmAlgId
.algorithm
);
287 CL_snaccOidToCssm(snaccAlgId
.algorithm
, outOid
, alloc
);
289 /* parameters as AsnAny - optional - for now just pass back the raw bytes */
290 if(snaccAlgId
.parameters
!= NULL
) {
291 CSM_Buffer
*cbuf
= snaccAlgId
.parameters
->value
;
292 cssmAlgId
.parameters
.Data
= (uint8
*)alloc
.malloc(cbuf
->Length());
293 cssmAlgId
.parameters
.Length
= cbuf
->Length();
294 memmove(cssmAlgId
.parameters
.Data
, cbuf
->Access(),
295 cssmAlgId
.parameters
.Length
);
299 /* convert between uint32-style CSSM algorithm and snacc-style AsnOid */
300 CSSM_ALGORITHMS
CL_snaccOidToCssmAlg(
303 AlgOidCache
&oc
= algOidCache();
305 CSSM_ALGORITHMS cssmAlg
= 0;
306 if(oid
== oc
.mRsaEncryption
) {
307 cssmAlg
= CSSM_ALGID_RSA
;
309 else if(oid
== oc
.mMd2WithRSAEncryption
) {
310 cssmAlg
= CSSM_ALGID_MD2WithRSA
;
312 else if(oid
== oc
.mMd5WithRSAEncryption
) {
313 cssmAlg
= CSSM_ALGID_MD5WithRSA
;
315 else if(oid
== oc
.mSha1withRSAEncryption
) {
316 cssmAlg
= CSSM_ALGID_SHA1WithRSA
;
318 else if(oid
== oc
.mId_dsa
) {
319 cssmAlg
= CSSM_ALGID_DSA
;
321 else if(oid
== oc
.mId_dsa_with_sha1
) {
322 cssmAlg
= CSSM_ALGID_SHA1WithDSA
;
324 else if(oid
== oc
.mAppleFee
) {
325 cssmAlg
= CSSM_ALGID_FEE
;
327 else if(oid
== oc
.mAppleAsc
) {
328 cssmAlg
= CSSM_ALGID_ASC
;
330 else if(oid
== oc
.mAppleFeeMD5
) {
331 cssmAlg
= CSSM_ALGID_FEE_MD5
;
333 else if(oid
== oc
.mAppleFeeSHA1
) {
334 cssmAlg
= CSSM_ALGID_FEE_SHA1
;
336 else if(oid
== oc
.mAppleFeed
) {
337 cssmAlg
= CSSM_ALGID_FEED
;
339 else if(oid
== oc
.mAppleFeedExp
) {
340 cssmAlg
= CSSM_ALGID_FEEDEXP
;
342 else if(oid
== oc
.mAppleECDSA
) {
343 cssmAlg
= CSSM_ALGID_SHA1WithECDSA
;
347 errorLog0("snaccOidToCssmAlg: unknown alg\n");
349 printf("Bogus OID: "); oid
.Print(cout
);
352 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
357 void CL_cssmAlgToSnaccOid(
358 CSSM_ALGORITHMS cssmAlg
,
363 oid
.ReSet(rsaEncryption_arc
);
365 case CSSM_ALGID_MD2WithRSA
:
366 oid
.ReSet(md2WithRSAEncryption_arc
);
368 case CSSM_ALGID_MD5WithRSA
:
369 oid
.ReSet(md5WithRSAEncryption_arc
);
371 case CSSM_ALGID_SHA1WithRSA
:
372 oid
.ReSet(sha1withRSAEncryption_arc
);
375 oid
.ReSet(id_dsa_arc
);
377 case CSSM_ALGID_SHA1WithDSA
:
378 oid
.ReSet(id_dsa_with_sha1_arc
);
381 oid
.ReSet(appleFee_arc
);
384 oid
.ReSet(appleAsc_arc
);
386 case CSSM_ALGID_FEE_MD5
:
387 oid
.ReSet(appleFeeMD5_arc
);
389 case CSSM_ALGID_FEE_SHA1
:
390 oid
.ReSet(appleFeeSHA1_arc
);
392 case CSSM_ALGID_FEED
:
393 oid
.ReSet(appleFeed_arc
);
395 case CSSM_ALGID_FEEDEXP
:
396 oid
.ReSet(appleFeedExp_arc
);
398 case CSSM_ALGID_SHA1WithECDSA
:
399 oid
.ReSet(appleECDSA_arc
);
403 errorLog1("cssmAlgToSnaccOid: unknown alg (%d)\n", (int)cssmAlg
);
404 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
408 /* set up a encoded NULL for AlgorithmIdentifier.parameters */
409 void CL_nullAlgParams(
410 AlgorithmIdentifier
&snaccAlgId
)
412 snaccAlgId
.parameters
= new AsnAny
;
413 char encodedNull
[2] = {NULLTYPE_TAG_CODE
, 0};
414 CSM_Buffer
*cbuf
= new CSM_Buffer(encodedNull
, 2);
415 snaccAlgId
.parameters
->value
= cbuf
;
418 /* AsnOcts --> CSSM_DATA */
419 void CL_AsnOctsToCssmData(
422 CssmAllocator
&alloc
)
424 const char *cp
= octs
;
425 CssmAutoData
aData(alloc
, (uint8
*)cp
, octs
.Len());
426 cdata
= aData
.release();
429 #define MAX_NAME_SIZE (4 * 1024)
431 /* snacc-style GeneralNames --> CE_GeneralNames */
432 /* GeneralNames from sm_x509cmn.h */
433 void CL_snaccGeneralNamesToCdsa(
434 GeneralNames
&snaccObj
,
435 CE_GeneralNames
&cdsaObj
,
436 CssmAllocator
&alloc
)
438 cdsaObj
.numNames
= snaccObj
.Count();
439 if(cdsaObj
.numNames
== 0) {
440 cdsaObj
.generalName
= NULL
;
443 cdsaObj
.generalName
= (CE_GeneralName
*)alloc
.malloc(
444 cdsaObj
.numNames
* sizeof(CE_GeneralName
));
445 snaccObj
.SetCurrToFirst();
446 CssmAutoData
aData(alloc
);
447 for(unsigned i
=0; i
<cdsaObj
.numNames
; i
++) {
448 CE_GeneralName
*currCdsaName
= &cdsaObj
.generalName
[i
];
449 GeneralName
*currSnaccName
= snaccObj
.Curr();
451 /* just take the simple ones for now */
454 AsnType
*toBeEncoded
= NULL
;
455 bool freeSrc
= false;
456 switch(currSnaccName
->choiceId
) {
457 case GeneralName::otherNameCid
:
458 /* OTHER_NAME, AsnOid */
459 currCdsaName
->nameType
= GNT_OtherName
;
460 src
= *currSnaccName
->otherName
;
461 len
= currSnaccName
->otherName
->Len();
463 case GeneralName::rfc822NameCid
:
464 /* IA5String, AsnOcts */
465 currCdsaName
->nameType
= GNT_RFC822Name
;
466 src
= *currSnaccName
->rfc822Name
;
467 len
= currSnaccName
->rfc822Name
->Len();
469 case GeneralName::dNSNameCid
:
470 /* IA5String, AsnOcts */
471 currCdsaName
->nameType
= GNT_DNSName
;
472 src
= *currSnaccName
->dNSName
;
473 len
= currSnaccName
->dNSName
->Len();
475 case GeneralName::x400AddressCid
:
476 /* ORAddress from sm_x411mtsas */
477 currCdsaName
->nameType
= GNT_X400Address
;
478 toBeEncoded
= currSnaccName
->x400Address
;
480 case GeneralName::directoryNameCid
:
481 /* Name from sm_x501if */
482 /* We actually have to to deal with this in CertFields.cpp;
483 * it'll be easy to support this (with a mod to
486 currCdsaName
->nameType
= GNT_DirectoryName
;
487 toBeEncoded
= currSnaccName
->directoryName
;
489 case GeneralName::ediPartyNameCid
:
490 /* EDIPartyName from sm_x509cmn */
491 currCdsaName
->nameType
= GNT_EdiPartyName
;
492 toBeEncoded
= currSnaccName
->ediPartyName
;
494 case GeneralName::uniformResourceIdentifierCid
:
495 /* IA5String, AsnOcts */
496 currCdsaName
->nameType
= GNT_URI
;
497 src
= *currSnaccName
->uniformResourceIdentifier
;
498 len
= currSnaccName
->uniformResourceIdentifier
->Len();
500 case GeneralName::iPAddressCid
:
502 currCdsaName
->nameType
= GNT_IPAddress
;
503 src
= *currSnaccName
->iPAddress
;
504 len
= currSnaccName
->iPAddress
->Len();
506 case GeneralName::registeredIDCid
:
508 currCdsaName
->nameType
= GNT_RegisteredID
;
509 src
= *currSnaccName
->registeredID
;
510 len
= currSnaccName
->registeredID
->Len();
514 /* punt - encode the complex object and give caller the encoded
516 CASSERT(toBeEncoded
!= NULL
);
517 SC_encodeAsnObj(*toBeEncoded
, aData
, MAX_NAME_SIZE
);
519 len
= aData
.length();
522 currCdsaName
->berEncoded
= CSSM_TRUE
;
525 CASSERT(toBeEncoded
== NULL
);
526 currCdsaName
->berEncoded
= CSSM_FALSE
;
529 /* src --> currCdsaName->name */
530 currCdsaName
->name
.Data
= (uint8
*)alloc
.malloc(len
);
531 currCdsaName
->name
.Length
= len
;
532 memmove(currCdsaName
->name
.Data
, src
, len
);
540 /* CE_GeneralNames --> snacc-style GeneralNames */
541 /* GeneralNames from sm_x509cmn.h */
542 GeneralNames
*CL_cdsaGeneralNamesToSnacc(
543 CE_GeneralNames
&cdsaObj
)
545 GeneralNames
*snaccObj
= new GeneralNames
;
546 bool abortFlag
= false; // true --> invalid incoming field
547 CssmAllocator
&alloc
= CssmAllocator::standard();
549 for(unsigned i
=0; i
<cdsaObj
.numNames
; i
++) {
550 CE_GeneralName
*currCdsaName
= &cdsaObj
.generalName
[i
];
551 char *rawData
= reinterpret_cast<char *>(currCdsaName
->name
.Data
);
552 unsigned rawDataLen
= currCdsaName
->name
.Length
;
553 GeneralName
*currSnaccName
= snaccObj
->Append();
554 CssmData
&berCdata
= CssmData::overlay(currCdsaName
->name
);
555 CssmRemoteData
berData(alloc
, berCdata
);
556 switch(currCdsaName
->nameType
) {
558 /* OTHER_NAME, AsnOid */
559 if(currCdsaName
->berEncoded
) {
563 currSnaccName
->choiceId
= GeneralName::otherNameCid
;
564 currSnaccName
->otherName
= new AsnOid(rawData
, rawDataLen
);
569 if(currCdsaName
->berEncoded
) {
573 currSnaccName
->choiceId
= GeneralName::rfc822NameCid
;
574 currSnaccName
->rfc822Name
= new IA5String(rawData
, rawDataLen
);
578 if(currCdsaName
->berEncoded
) {
582 currSnaccName
->choiceId
= GeneralName::dNSNameCid
;
583 currSnaccName
->rfc822Name
= new IA5String(rawData
, rawDataLen
);
586 case GNT_X400Address
:
587 /* ORAddress from sm_x411mtsas */
588 if(!currCdsaName
->berEncoded
) {
592 currSnaccName
->choiceId
= GeneralName::x400AddressCid
;
593 currSnaccName
->x400Address
= new ORAddress
;
595 SC_decodeAsnObj(berData
, *currSnaccName
->x400Address
);
601 case GNT_DirectoryName
:
602 /* Name from sm_x501if */
603 /* We actually have to to deal with this in CertFields.cpp;
604 * it'll be easy to support this (with a mod to
607 if(!currCdsaName
->berEncoded
) {
611 currSnaccName
->choiceId
= GeneralName::directoryNameCid
;
612 currSnaccName
->directoryName
= new Name
;
614 SC_decodeAsnObj(berData
, *currSnaccName
->directoryName
);
621 case GNT_EdiPartyName
:
622 /* EDIPartyName from sm_x509cmn */
623 if(!currCdsaName
->berEncoded
) {
627 currSnaccName
->choiceId
= GeneralName::ediPartyNameCid
;
628 currSnaccName
->ediPartyName
= new EDIPartyName
;
630 SC_decodeAsnObj(berData
, *currSnaccName
->ediPartyName
);
639 if(currCdsaName
->berEncoded
) {
643 currSnaccName
->choiceId
= GeneralName::uniformResourceIdentifierCid
;
644 currSnaccName
->uniformResourceIdentifier
=
645 new IA5String(rawData
, rawDataLen
);
650 if(currCdsaName
->berEncoded
) {
654 currSnaccName
->choiceId
= GeneralName::iPAddressCid
;
655 currSnaccName
->iPAddress
= new AsnOcts(rawData
, rawDataLen
);
657 case GNT_RegisteredID
:
659 if(currCdsaName
->berEncoded
) {
663 currSnaccName
->choiceId
= GeneralName::registeredIDCid
;
664 currSnaccName
->registeredID
= new AsnOid(rawData
, rawDataLen
);
674 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
679 void CL_normalizeString(
683 char *pCh
= strPtr
; // working ptr
684 char *pD
= pCh
; // start of good string chars
685 char *pEos
= pCh
+ strLen
- 1;
691 /* adjust if Length included NULL terminator */
696 /* Remove trailing spaces */
697 while(isspace(*pEos
)) {
701 /* Point to one past last non-space character */
706 *pCh
= toupper(*pCh
);
710 /* clean out whitespace */
712 * 1. skip all leading whitespace
715 while(isspace(*pCh
) && (pCh
< pEos
)) {
720 * 2. eliminate multiple whitespace.
721 * pCh points to first non-white char.
722 * pD still points to start of string
727 *pD
++ = ch
; // normal case
729 /* skip 'til next nonwhite */
730 while(isspace(*pCh
) && (pCh
< pEos
)) {
736 strLen
= pD
- strPtr
;
740 * Normalize an RDN. Per RFC2459 (4.1.2.4), printable strings are case
741 * insensitive and we're supposed to ignore leading and trailing
742 * whitespace, and collapse multiple whitespace characters into one.
744 void CL_normalizeX509Name(
746 CssmAllocator
&alloc
)
748 RDNSequence
*rdns
= name
.rDNSequence
;
749 int numRdns
= rdns
->Count();
750 if((rdns
== NULL
) || (numRdns
== 0)) {
751 /* not technically an error */
755 rdns
->SetCurrElmt(0);
756 for(int rdnDex
=0; rdnDex
<numRdns
; rdnDex
++) {
758 RelativeDistinguishedName
*rdn
= rdns
->Curr();
760 /* not sure how this can happen... */
761 dprintf1("clNormalizeX509Name: NULL rdn at index %d\n", rdnDex
);
765 int numAttrs
= rdn
->Count();
767 dprintf1("clNormalizeX509Name: zero numAttrs at index %d\n", rdnDex
);
772 /* descend into array of attribute/values */
774 for(int attrDex
=0; attrDex
<numAttrs
; attrDex
++) {
776 AttributeTypeAndDistinguishedValue
*att
= rdn
->Curr();
778 /* not sure how this can happen... */
779 dprintf1("clNormalizeX509Name: NULL att at index %d\n", attrDex
);
785 * att->value is an AsnAny (CSM_Buffer) containing an encoded
786 * string - supposedly a DirectoryString, but some certs put an
787 * IA5String here which is not handled by DirectoryString.
789 * (See e.g. the Thawte serverbasic cert, which has an email
790 * address in IA5String format.) In the IA5String case we skip the
793 * Anyway, figure out what's there, snag the raw string, normalize the
794 * string, cook up an appropriate DirectoryString for it, encode the
795 * result, and put the encoding back in att->value.
797 CSM_Buffer
*cbuf
= att
->value
.value
;
798 DirectoryString dirStr
;
799 char *cbufData
= const_cast<char *>(cbuf
->Access());
800 CssmData
encodedStr(cbufData
, cbuf
->Length());
802 /* avoid exception if this is an IA5String... */
803 char tagByte
= cbufData
[0];
804 if((tagByte
== (UNIV
| PRIM
| IA5STRING_TAG_CODE
)) ||
805 (tagByte
== (UNIV
| CONS
| IA5STRING_TAG_CODE
))) {
806 /* can't normalize */
810 SC_decodeAsnObj(encodedStr
, dirStr
);
813 /* can't normalize */
814 errorLog0("clNormalizeX509Name: malformed DirectoryString (1)\n");
818 /* normalize, we don't need to know what kind of string it is */
819 char *strPtr
= *dirStr
.teletexString
;
820 int newLen
= dirStr
.teletexString
->Len();
821 CL_normalizeString(strPtr
, newLen
);
823 /* set new AsnOcts data from normalized version, freeing old */
824 dirStr
.teletexString
->ReSet(strPtr
, newLen
);
827 CssmAutoData
normEncoded(alloc
);
828 SC_encodeAsnObj(dirStr
, normEncoded
, newLen
+ 8);
830 /* set new AsnAny data */
831 cbuf
->Set((char *)normEncoded
.data(), normEncoded
.length());
834 } /* for each attribute/value */
840 * Obtain a CSSM_KEY from a SubjectPublicKeyInfo, inferring as much as we can
841 * from required fields (subjectPublicKeyInfo) and extensions (for
842 * KeyUse, obtained from the optional DecodedCert).
844 CSSM_KEY_PTR
CL_extractCSSMKey(
845 SubjectPublicKeyInfo
&snaccKeyInfo
,
846 CssmAllocator
&alloc
,
847 const DecodedCert
*decodedCert
) // optional
849 CSSM_KEY_PTR cssmKey
= (CSSM_KEY_PTR
) alloc
.malloc(sizeof(CSSM_KEY
));
850 memset(cssmKey
, 0, sizeof(CSSM_KEY
));
851 CSSM_KEYHEADER
&hdr
= cssmKey
->KeyHeader
;
852 CssmRemoteData
keyData(alloc
, cssmKey
->KeyData
);
854 hdr
.HeaderVersion
= CSSM_KEYHEADER_VERSION
;
856 hdr
.BlobType
= CSSM_KEYBLOB_RAW
;
857 hdr
.AlgorithmId
= CL_snaccOidToCssmAlg(snaccKeyInfo
.algorithm
->algorithm
);
860 * Format inferred from AlgorithmId. I have never seen these defined
861 * anywhere, e.g., whart's the format of an RSA public key in a cert?
862 * X509 certainly doesn't say. However. the following two cases are known
865 switch(hdr
.AlgorithmId
) {
867 hdr
.Format
= CSSM_KEYBLOB_RAW_FORMAT_PKCS1
;
870 hdr
.Format
= CSSM_KEYBLOB_RAW_FORMAT_FIPS186
;
873 /* CSSM_KEYBLOB_RAW_FORMAT_NONE --> DER encoded */
874 hdr
.Format
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
878 hdr
.Format
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
880 hdr
.KeyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
882 /* KeyUsage inferred from extensions */
884 hdr
.KeyUsage
= decodedCert
->inferKeyUsage();
887 hdr
.KeyUsage
= CSSM_KEYUSE_ANY
;
890 /* start/end date unknown, leave zero */
891 hdr
.WrapAlgorithmId
= CSSM_ALGID_NONE
;
892 hdr
.WrapMode
= CSSM_ALGMODE_NONE
;
895 * subjectPublicKeyInfo.subjectPublicKey (AsnBits) ==> KeyData
897 SC_asnBitsToCssmData(snaccKeyInfo
.subjectPublicKey
, keyData
);
901 * LogicalKeySizeInBits - ask the CSP
903 CSSM_CSP_HANDLE cspHand
= getGlobalCspHand(true);
904 CSSM_KEY_SIZE keySize
;
906 crtn
= CSSM_QueryKeySizeInBits(cspHand
, CSSM_INVALID_HANDLE
, cssmKey
, &keySize
);
908 CssmError::throwMe(crtn
);
910 cssmKey
->KeyHeader
.LogicalKeySizeInBits
=
911 keySize
.LogicalKeySizeInBits
;
921 CSSM_KEY_PTR cssmKey
,
922 CssmAllocator
&alloc
,
925 if(cssmKey
== NULL
) {
928 alloc
.free(cssmKey
->KeyData
.Data
);
929 memset(cssmKey
, 0, sizeof(CSSM_KEY
));