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 "cldebugging.h"
28 #include <Security/pkcs1oids.h>
29 #include <Security/cdsaUtils.h>
30 #include <Security/cssmapple.h>
31 #include <Security/appleoids.h>
32 #include <Security/globalizer.h>
34 #define DEBUG_DECODE 0
36 #define ddprintf(x) printf x
42 * AsnOid "constants" which we construct and cache on demand to avoid the
43 * somewhat expensive op of constructing them every time we test for equality
44 * in CL_snaccOidToCssmAlg.
50 mRsaEncryption(rsaEncryption_arc
),
51 mMd2WithRSAEncryption(md2WithRSAEncryption_arc
),
52 mMd5WithRSAEncryption(md5WithRSAEncryption_arc
),
53 mSha1withRSAEncryption(sha1withRSAEncryption_arc
),
55 mId_dsa_with_sha1(id_dsa_with_sha1_arc
),
56 mAppleFee(appleFee_arc
),
57 mAppleAsc(appleAsc_arc
),
58 mAppleFeeMD5(appleFeeMD5_arc
),
59 mAppleFeeSHA1(appleFeeSHA1_arc
),
60 mAppleFeed(appleFeed_arc
),
61 mAppleFeedExp(appleFeedExp_arc
),
62 mAppleECDSA(appleECDSA_arc
)
65 AsnOid mRsaEncryption
;
66 AsnOid mMd2WithRSAEncryption
;
67 AsnOid mMd5WithRSAEncryption
;
68 AsnOid mSha1withRSAEncryption
;
70 AsnOid mId_dsa_with_sha1
;
80 static ModuleNexus
<AlgOidCache
> algOidCache
;
83 * To ensure a secure means of signing and verifying TBSCert blobs, we
84 * provide these functions to encode and decode just the top-level
85 * elements of a certificate. Snacc doesn't allow you to specify, for
86 * example, a fully encoded TBSCert prior to encoding the whole cert after
87 * signing it - you have to decode the TBSCert, put it and the other
88 * components into a Cert, and then encode the whole thing. Unfortunately
89 * there is no guarantee that when you decode and re-encode a TBSCert blob,
90 * you get the same thing you started with (although with DER rules, as
91 * opposed to BER rules, you should). Thus when signing, we sign the TBSCert
92 * and encode the signed cert here without ever decoding the TBSCert (or,
93 * at least, without using the decoded version to get the encoded TBS blob).
97 CL_certDecodeComponents(
98 const CssmData
&signedCert
, // DER-encoded
99 CssmOwnedData
&TBSCert
, // still DER-encoded
100 CssmOwnedData
&algId
, // ditto
101 CssmOwnedData
&rawSig
) // raw bits (not an encoded AsnBits)
103 CssmAutoData
encodedSig(rawSig
.allocator
);
105 /* drop signedCert into an AsnBuf for processing */
107 buf
.InstallData(reinterpret_cast<char *>(signedCert
.data()), signedCert
.length());
109 /* based on snacc-generated Certificate::BDec() and BDecContent() */
111 AsnLen bytesDecoded
= 0;
112 AsnLen decLen
; // from BDecLen
113 AsnLen totalLen
; // including tag and ASN length
114 char *elemStart
; // ptr to start of element, including tag
118 if ((rtn
= setjmp (env
)) == 0) {
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: longjmp 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(md2WithRSAEncryption_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 switch(currSnaccName
->choiceId
) {
456 case GeneralName::otherNameCid
:
457 /* OTHER_NAME, AsnOid */
458 currCdsaName
->nameType
= GNT_OtherName
;
459 src
= *currSnaccName
->otherName
;
460 len
= currSnaccName
->otherName
->Len();
462 case GeneralName::rfc822NameCid
:
463 /* IA5String, AsnOcts */
464 currCdsaName
->nameType
= GNT_RFC822Name
;
465 src
= *currSnaccName
->rfc822Name
;
466 len
= currSnaccName
->rfc822Name
->Len();
468 case GeneralName::dNSNameCid
:
469 /* IA5String, AsnOcts */
470 currCdsaName
->nameType
= GNT_DNSName
;
471 src
= *currSnaccName
->dNSName
;
472 len
= currSnaccName
->dNSName
->Len();
474 case GeneralName::x400AddressCid
:
475 /* ORAddress from sm_x411mtsas */
476 currCdsaName
->nameType
= GNT_X400Address
;
477 toBeEncoded
= currSnaccName
->x400Address
;
479 case GeneralName::directoryNameCid
:
480 /* Name from sm_x501if */
481 /* We actually have to to deal with this in CertFields.cpp;
482 * it'll be easy to support this (with a mod to
485 currCdsaName
->nameType
= GNT_DirectoryName
;
486 toBeEncoded
= currSnaccName
->directoryName
;
488 case GeneralName::ediPartyNameCid
:
489 /* EDIPartyName from sm_x509cmn */
490 currCdsaName
->nameType
= GNT_EdiPartyName
;
491 toBeEncoded
= currSnaccName
->ediPartyName
;
493 case GeneralName::uniformResourceIdentifierCid
:
494 /* IA5String, AsnOcts */
495 currCdsaName
->nameType
= GNT_URI
;
496 src
= *currSnaccName
->uniformResourceIdentifier
;
497 len
= currSnaccName
->uniformResourceIdentifier
->Len();
499 case GeneralName::iPAddressCid
:
501 currCdsaName
->nameType
= GNT_IPAddress
;
502 src
= *currSnaccName
->iPAddress
;
503 len
= currSnaccName
->iPAddress
->Len();
505 case GeneralName::registeredIDCid
:
507 currCdsaName
->nameType
= GNT_RegisteredID
;
508 src
= *currSnaccName
->registeredID
;
509 len
= currSnaccName
->registeredID
->Len();
513 /* punt - encode the complex object and give caller the encoded
515 CASSERT(toBeEncoded
!= NULL
);
516 SC_encodeAsnObj(*toBeEncoded
, aData
, MAX_NAME_SIZE
);
518 len
= aData
.length();
520 currCdsaName
->berEncoded
= CSSM_TRUE
;
523 CASSERT(toBeEncoded
== NULL
);
524 currCdsaName
->berEncoded
= CSSM_FALSE
;
527 /* src --> currCdsaName->name */
528 currCdsaName
->name
.Data
= (uint8
*)alloc
.malloc(len
);
529 currCdsaName
->name
.Length
= len
;
530 memmove(currCdsaName
->name
.Data
, src
, len
);
536 /* CE_GeneralNames --> snacc-style GeneralNames */
537 /* GeneralNames from sm_x509cmn.h */
538 GeneralNames
*CL_cdsaGeneralNamesToSnacc(
539 CE_GeneralNames
&cdsaObj
)
541 GeneralNames
*snaccObj
= new GeneralNames
;
542 bool abortFlag
= false; // true --> invalid incoming field
543 CssmAllocator
&alloc
= CssmAllocator::standard();
545 for(unsigned i
=0; i
<cdsaObj
.numNames
; i
++) {
546 CE_GeneralName
*currCdsaName
= &cdsaObj
.generalName
[i
];
547 char *rawData
= reinterpret_cast<char *>(currCdsaName
->name
.Data
);
548 unsigned rawDataLen
= currCdsaName
->name
.Length
;
549 GeneralName
*currSnaccName
= snaccObj
->Append();
550 CssmData
&berCdata
= CssmData::overlay(currCdsaName
->name
);
551 CssmRemoteData
berData(alloc
, berCdata
);
552 switch(currCdsaName
->nameType
) {
554 /* OTHER_NAME, AsnOid */
555 if(currCdsaName
->berEncoded
) {
559 currSnaccName
->choiceId
= GeneralName::otherNameCid
;
560 currSnaccName
->otherName
= new AsnOid(rawData
, rawDataLen
);
565 if(currCdsaName
->berEncoded
) {
569 currSnaccName
->choiceId
= GeneralName::rfc822NameCid
;
570 currSnaccName
->rfc822Name
= new IA5String(rawData
, rawDataLen
);
574 if(currCdsaName
->berEncoded
) {
578 currSnaccName
->choiceId
= GeneralName::dNSNameCid
;
579 currSnaccName
->rfc822Name
= new IA5String(rawData
, rawDataLen
);
582 case GNT_X400Address
:
583 /* ORAddress from sm_x411mtsas */
584 if(!currCdsaName
->berEncoded
) {
588 currSnaccName
->choiceId
= GeneralName::x400AddressCid
;
589 currSnaccName
->x400Address
= new ORAddress
;
591 SC_decodeAsnObj(berData
, *currSnaccName
->x400Address
);
597 case GNT_DirectoryName
:
598 /* Name from sm_x501if */
599 /* We actually have to to deal with this in CertFields.cpp;
600 * it'll be easy to support this (with a mod to
603 if(!currCdsaName
->berEncoded
) {
607 currSnaccName
->choiceId
= GeneralName::directoryNameCid
;
608 currSnaccName
->directoryName
= new Name
;
610 SC_decodeAsnObj(berData
, *currSnaccName
->directoryName
);
617 case GNT_EdiPartyName
:
618 /* EDIPartyName from sm_x509cmn */
619 if(!currCdsaName
->berEncoded
) {
623 currSnaccName
->choiceId
= GeneralName::ediPartyNameCid
;
624 currSnaccName
->ediPartyName
= new EDIPartyName
;
626 SC_decodeAsnObj(berData
, *currSnaccName
->ediPartyName
);
635 if(currCdsaName
->berEncoded
) {
639 currSnaccName
->choiceId
= GeneralName::uniformResourceIdentifierCid
;
640 currSnaccName
->uniformResourceIdentifier
=
641 new IA5String(rawData
, rawDataLen
);
646 if(currCdsaName
->berEncoded
) {
650 currSnaccName
->choiceId
= GeneralName::iPAddressCid
;
651 currSnaccName
->iPAddress
= new AsnOcts(rawData
, rawDataLen
);
653 case GNT_RegisteredID
:
655 if(currCdsaName
->berEncoded
) {
659 currSnaccName
->choiceId
= GeneralName::registeredIDCid
;
660 currSnaccName
->registeredID
= new AsnOid(rawData
, rawDataLen
);
670 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
675 void CL_normalizeString(
679 char *pCh
= strPtr
; // working ptr
680 char *pD
= pCh
; // start of good string chars
681 char *pEos
= pCh
+ strLen
- 1;
687 /* adjust if Length included NULL terminator */
692 /* Remove trailing spaces */
693 while(isspace(*pEos
)) {
697 /* Point to one past last non-space character */
702 *pCh
++ = toupper(*pCh
);
705 /* clean out whitespace */
707 * 1. skip all leading whitespace
710 while(isspace(*pCh
) && (pCh
< pEos
)) {
715 * 2. eliminate multiple whitespace.
716 * pCh points to first non-white char.
717 * pD still points to start of string
722 *pD
++ = ch
; // normal case
724 /* skip 'til next nonwhite */
725 while(isspace(*pCh
) && (pCh
< pEos
)) {
731 strLen
= pD
- strPtr
;
735 * Normalize an RDN. Per RFC2459 (4.1.2.4), printable strings are case
736 * insensitive and we're supposed to ignore leading and trailing
737 * whitespace, and collapse multiple whitespace characters into one.
739 void CL_normalizeX509Name(
741 CssmAllocator
&alloc
)
743 RDNSequence
*rdns
= name
.rDNSequence
;
744 int numRdns
= rdns
->Count();
745 if((rdns
== NULL
) || (numRdns
== 0)) {
746 /* not technically an error */
750 rdns
->SetCurrElmt(0);
751 for(int rdnDex
=0; rdnDex
<numRdns
; rdnDex
++) {
753 RelativeDistinguishedName
*rdn
= rdns
->Curr();
755 /* not sure how this can happen... */
756 dprintf1("clNormalizeX509Name: NULL rdn at index %d\n", rdnDex
);
760 int numAttrs
= rdn
->Count();
762 dprintf1("clNormalizeX509Name: zero numAttrs at index %d\n", rdnDex
);
767 /* descend into array of attribute/values */
769 for(int attrDex
=0; attrDex
<numAttrs
; attrDex
++) {
771 AttributeTypeAndDistinguishedValue
*att
= rdn
->Curr();
773 /* not sure how this can happen... */
774 dprintf1("clNormalizeX509Name: NULL att at index %d\n", attrDex
);
780 * att->value is an AsnAny (CSM_Buffer) containing an encoded
781 * string - supposedly a DirectoryString, but some certs put an
782 * IA5String here which is not handled by DirectoryString.
784 * (See e.g. the Thawte serverbasic cert, which has an email
785 * address in IA5String format.) In the IA5String case we skip the
788 * Anyway, figure out what's there, snag the raw string, normalize the
789 * string, cook up an appropriate DirectoryString for it, encode the
790 * result, and put the encoding back in att->value.
792 CSM_Buffer
*cbuf
= att
->value
.value
;
793 DirectoryString dirStr
;
794 char *cbufData
= const_cast<char *>(cbuf
->Access());
795 CssmData
encodedStr(cbufData
, cbuf
->Length());
797 /* avoid exception if this is an IA5String... */
798 char tagByte
= cbufData
[0];
799 if((tagByte
== (UNIV
| PRIM
| IA5STRING_TAG_CODE
)) ||
800 (tagByte
== (UNIV
| CONS
| IA5STRING_TAG_CODE
))) {
801 /* can't normalize */
805 SC_decodeAsnObj(encodedStr
, dirStr
);
808 /* can't normalize */
809 errorLog0("clNormalizeX509Name: malformed DirectoryString (1)\n");
813 /* normalize, we don't need to know what kind of string it is */
814 char *strPtr
= *dirStr
.teletexString
;
815 int newLen
= dirStr
.teletexString
->Len();
816 CL_normalizeString(strPtr
, newLen
);
818 /* set new AsnOcts data from normalized version, freeing old */
819 dirStr
.teletexString
->ReSet(strPtr
, newLen
);
822 CssmAutoData
normEncoded(alloc
);
823 SC_encodeAsnObj(dirStr
, normEncoded
, newLen
+ 8);
825 /* set new AsnAny data */
826 cbuf
->Set((char *)normEncoded
.data(), normEncoded
.length());
829 } /* for each attribute/value */