]> git.saurik.com Git - apple/security.git/blame - AppleX509CL/SnaccUtils.cpp
Security-54.1.9.tar.gz
[apple/security.git] / AppleX509CL / SnaccUtils.cpp
CommitLineData
bac41a7b
A
1/*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19/*
20 * CertSNACC.cpp - snacc-related cert functions
21 *
22 * Created 9/1/2000 by Doug Mitchell.
23 * Copyright (c) 2000 by Apple Computer.
24 */
25
26#include "SnaccUtils.h"
29654253 27#include "CSPAttacher.h"
bac41a7b
A
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>
34
35#define DEBUG_DECODE 0
36#if DEBUG_DECODE
37#define ddprintf(x) printf x
38#else
39#define ddprintf(x)
40#endif
41
42/*
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.
46 */
47class AlgOidCache
48{
49public:
50 AlgOidCache() :
51 mRsaEncryption(rsaEncryption_arc),
52 mMd2WithRSAEncryption(md2WithRSAEncryption_arc),
53 mMd5WithRSAEncryption(md5WithRSAEncryption_arc),
54 mSha1withRSAEncryption(sha1withRSAEncryption_arc),
55 mId_dsa(id_dsa_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)
64 { }
65
66 AsnOid mRsaEncryption;
67 AsnOid mMd2WithRSAEncryption;
68 AsnOid mMd5WithRSAEncryption;
69 AsnOid mSha1withRSAEncryption;
70 AsnOid mId_dsa;
71 AsnOid mId_dsa_with_sha1;
72 AsnOid mAppleFee;
73 AsnOid mAppleAsc;
74 AsnOid mAppleFeeMD5;
75 AsnOid mAppleFeeSHA1;
76 AsnOid mAppleFeed;
77 AsnOid mAppleFeedExp;
78 AsnOid mAppleECDSA;
79};
80
81static ModuleNexus<AlgOidCache> algOidCache;
82
83/*
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).
95 */
96
97void
98CL_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)
103{
104 CssmAutoData encodedSig(rawSig.allocator);
105
106 /* drop signedCert into an AsnBuf for processing */
107 AsnBuf buf;
108 buf.InstallData(reinterpret_cast<char *>(signedCert.data()), signedCert.length());
109
110 /* based on snacc-generated Certificate::BDec() and BDecContent() */
111 AsnTag tag;
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
116
bac41a7b 117 ENV_TYPE env;
29654253 118 try {
bac41a7b
A
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);
123 }
124 decLen = BDecLen (buf, bytesDecoded, env); // of total
125 /* FIXME - we should be able to ensure right here that we have enough */
126
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);
134 }
135
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()));
139 buf.Skip(decLen);
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]));
145
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);
152 }
153 decLen = BDecLen (buf, bytesDecoded, env);
154 totalLen = decLen + (bytesDecoded - (elemStart - buf.DataPtr()));
155 buf.Skip(decLen);
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]));
161
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);
169 }
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 "
174 "%02x %02x...\n",
175 totalLen, ((uint8 *)elemStart)[0], ((uint8 *)elemStart)[1],
176 ((uint8 *)elemStart)[2], ((uint8 *)elemStart)[3]));
177
178 /*
179 * encodedSig is a DER-encoded AsnBits. Decode for caller.
180 */
181 SC_decodeAsnBitsToCssmData(encodedSig.get(), rawSig);
182 ddprintf(("CL_certDecodeComponents: rawSig len %d\n", rawSig.length()));
183 /*
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.
187 */
188 }
29654253
A
189 catch(...) {
190 errorLog0("CL_CertDecodeComponents: throw during decode\n");
bac41a7b
A
191 TBSCert.reset();
192 algId.reset();
193 rawSig.reset();
194 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
195 }
196}
197
198/*
199 * Given pre-DER-encoded blobs, do the final encode step for a signed cert.
200 */
201void
202CL_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
207{
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);
213
214 /*
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.
219 */
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);
224
225 /* tag */
226 char *cp = (char *)signedCert.data();
227 *cp++ = UNIV | CONS | SEQ_TAG_CODE;
228
229 /* length */
230 SC_encodeLength(contentLen, cp, lenLen);
231 cp += lenLen;
232
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()));
241}
242
243/* malloc/copy a CsmmOid from a snacc-style AsnOid. */
244void CL_snaccOidToCssm(
245 const AsnOid &inOid,
246 CssmOid &outOid,
247 CssmAllocator &alloc)
248{
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);
253}
254
255/* convert algorithm identifier from CSSM format to snacc format */
256void CL_cssmAlgIdToSnacc (
257 const CSSM_X509_ALGORITHM_IDENTIFIER &cssmAlgId,
258 AlgorithmIdentifier &snaccAlgId)
259{
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;
271 }
272 else {
273 CL_nullAlgParams(snaccAlgId);
274 }
275}
276
277/* convert algorithm indentifier from snacc format to CSSM format */
278void CL_snaccAlgIdToCssm (
279 const AlgorithmIdentifier &snaccAlgId,
280 CSSM_X509_ALGORITHM_IDENTIFIER &cssmAlgId,
281 CssmAllocator &alloc)
282{
283 memset(&cssmAlgId, 0, sizeof(CSSM_X509_ALGORITHM_IDENTIFIER));
284
285 /* algorithm - required */
286 CssmOid &outOid = CssmOid::overlay(cssmAlgId.algorithm);
287 CL_snaccOidToCssm(snaccAlgId.algorithm, outOid, alloc);
288
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);
296 }
297}
298
299/* convert between uint32-style CSSM algorithm and snacc-style AsnOid */
300CSSM_ALGORITHMS CL_snaccOidToCssmAlg(
301 const AsnOid &oid)
302{
303 AlgOidCache &oc = algOidCache();
304
305 CSSM_ALGORITHMS cssmAlg = 0;
306 if(oid == oc.mRsaEncryption) {
307 cssmAlg = CSSM_ALGID_RSA;
308 }
309 else if(oid == oc.mMd2WithRSAEncryption) {
310 cssmAlg = CSSM_ALGID_MD2WithRSA;
311 }
312 else if(oid == oc.mMd5WithRSAEncryption) {
313 cssmAlg = CSSM_ALGID_MD5WithRSA;
314 }
315 else if(oid == oc.mSha1withRSAEncryption) {
316 cssmAlg = CSSM_ALGID_SHA1WithRSA;
317 }
318 else if(oid == oc.mId_dsa) {
319 cssmAlg = CSSM_ALGID_DSA;
320 }
321 else if(oid == oc.mId_dsa_with_sha1) {
322 cssmAlg = CSSM_ALGID_SHA1WithDSA;
323 }
324 else if(oid == oc.mAppleFee) {
325 cssmAlg = CSSM_ALGID_FEE;
326 }
327 else if(oid == oc.mAppleAsc) {
328 cssmAlg = CSSM_ALGID_ASC;
329 }
330 else if(oid == oc.mAppleFeeMD5) {
331 cssmAlg = CSSM_ALGID_FEE_MD5;
332 }
333 else if(oid == oc.mAppleFeeSHA1) {
334 cssmAlg = CSSM_ALGID_FEE_SHA1;
335 }
336 else if(oid == oc.mAppleFeed) {
337 cssmAlg = CSSM_ALGID_FEED;
338 }
339 else if(oid == oc.mAppleFeedExp) {
340 cssmAlg = CSSM_ALGID_FEEDEXP;
341 }
342 else if(oid == oc.mAppleECDSA) {
343 cssmAlg = CSSM_ALGID_SHA1WithECDSA;
344 }
345 /* etc. */
346 else {
347 errorLog0("snaccOidToCssmAlg: unknown alg\n");
348 #ifndef NDEBUG
349 printf("Bogus OID: "); oid.Print(cout);
350 printf("\n");
351 #endif
352 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
353 }
354 return cssmAlg;
355}
356
357void CL_cssmAlgToSnaccOid(
358 CSSM_ALGORITHMS cssmAlg,
359 AsnOid &oid)
360{
361 switch(cssmAlg) {
362 case CSSM_ALGID_RSA:
363 oid.ReSet(rsaEncryption_arc);
364 break;
365 case CSSM_ALGID_MD2WithRSA:
366 oid.ReSet(md2WithRSAEncryption_arc);
367 break;
368 case CSSM_ALGID_MD5WithRSA:
29654253 369 oid.ReSet(md5WithRSAEncryption_arc);
bac41a7b
A
370 break;
371 case CSSM_ALGID_SHA1WithRSA:
372 oid.ReSet(sha1withRSAEncryption_arc);
373 break;
374 case CSSM_ALGID_DSA:
375 oid.ReSet(id_dsa_arc);
376 break;
377 case CSSM_ALGID_SHA1WithDSA:
378 oid.ReSet(id_dsa_with_sha1_arc);
379 break;
380 case CSSM_ALGID_FEE:
381 oid.ReSet(appleFee_arc);
382 break;
383 case CSSM_ALGID_ASC:
384 oid.ReSet(appleAsc_arc);
385 break;
386 case CSSM_ALGID_FEE_MD5:
387 oid.ReSet(appleFeeMD5_arc);
388 break;
389 case CSSM_ALGID_FEE_SHA1:
390 oid.ReSet(appleFeeSHA1_arc);
391 break;
392 case CSSM_ALGID_FEED:
393 oid.ReSet(appleFeed_arc);
394 break;
395 case CSSM_ALGID_FEEDEXP:
396 oid.ReSet(appleFeedExp_arc);
397 break;
398 case CSSM_ALGID_SHA1WithECDSA:
399 oid.ReSet(appleECDSA_arc);
400 break;
401 /* etc. */
402 default:
403 errorLog1("cssmAlgToSnaccOid: unknown alg (%d)\n", (int)cssmAlg);
404 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
405 }
406}
407
408/* set up a encoded NULL for AlgorithmIdentifier.parameters */
409void CL_nullAlgParams(
410 AlgorithmIdentifier &snaccAlgId)
411{
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;
416}
417
418/* AsnOcts --> CSSM_DATA */
419void CL_AsnOctsToCssmData(
420 const AsnOcts &octs,
421 CSSM_DATA &cdata,
422 CssmAllocator &alloc)
423{
424 const char *cp = octs;
425 CssmAutoData aData(alloc, (uint8 *)cp, octs.Len());
426 cdata = aData.release();
427}
428
429#define MAX_NAME_SIZE (4 * 1024)
430
431/* snacc-style GeneralNames --> CE_GeneralNames */
432/* GeneralNames from sm_x509cmn.h */
433void CL_snaccGeneralNamesToCdsa(
434 GeneralNames &snaccObj,
435 CE_GeneralNames &cdsaObj,
436 CssmAllocator &alloc)
437{
438 cdsaObj.numNames = snaccObj.Count();
439 if(cdsaObj.numNames == 0) {
440 cdsaObj.generalName = NULL;
441 return;
442 }
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();
450
451 /* just take the simple ones for now */
452 char *src = NULL;
453 unsigned len = 0;
454 AsnType *toBeEncoded = NULL;
29654253 455 bool freeSrc = false;
bac41a7b
A
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();
462 break;
463 case GeneralName::rfc822NameCid:
464 /* IA5String, AsnOcts */
465 currCdsaName->nameType = GNT_RFC822Name;
466 src = *currSnaccName->rfc822Name;
467 len = currSnaccName->rfc822Name->Len();
468 break;
469 case GeneralName::dNSNameCid:
470 /* IA5String, AsnOcts */
471 currCdsaName->nameType = GNT_DNSName;
472 src = *currSnaccName->dNSName;
473 len = currSnaccName->dNSName->Len();
474 break;
475 case GeneralName::x400AddressCid:
476 /* ORAddress from sm_x411mtsas */
477 currCdsaName->nameType = GNT_X400Address;
478 toBeEncoded = currSnaccName->x400Address;
479 break;
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
484 * CE_GeneralName).
485 */
486 currCdsaName->nameType = GNT_DirectoryName;
487 toBeEncoded = currSnaccName->directoryName;
488 break;
489 case GeneralName::ediPartyNameCid:
490 /* EDIPartyName from sm_x509cmn */
491 currCdsaName->nameType = GNT_EdiPartyName;
492 toBeEncoded = currSnaccName->ediPartyName;
493 break;
494 case GeneralName::uniformResourceIdentifierCid:
495 /* IA5String, AsnOcts */
496 currCdsaName->nameType = GNT_URI;
497 src = *currSnaccName->uniformResourceIdentifier;
498 len = currSnaccName->uniformResourceIdentifier->Len();
499 break;
500 case GeneralName::iPAddressCid:
501 /* AsnOcts */
502 currCdsaName->nameType = GNT_IPAddress;
503 src = *currSnaccName->iPAddress;
504 len = currSnaccName->iPAddress->Len();
505 break;
506 case GeneralName::registeredIDCid:
507 /* AsnOid */
508 currCdsaName->nameType = GNT_RegisteredID;
509 src = *currSnaccName->registeredID;
510 len = currSnaccName->registeredID->Len();
511 break;
512 }
513 if(src == NULL) {
514 /* punt - encode the complex object and give caller the encoded
515 * bytes */
516 CASSERT(toBeEncoded != NULL);
517 SC_encodeAsnObj(*toBeEncoded, aData, MAX_NAME_SIZE);
518 src = aData;
519 len = aData.length();
520 aData.release();
29654253 521 freeSrc = true;
bac41a7b
A
522 currCdsaName->berEncoded = CSSM_TRUE;
523 }
524 else {
525 CASSERT(toBeEncoded == NULL);
526 currCdsaName->berEncoded = CSSM_FALSE;
527 }
528
529 /* src --> currCdsaName->name */
530 currCdsaName->name.Data = (uint8 *)alloc.malloc(len);
531 currCdsaName->name.Length = len;
532 memmove(currCdsaName->name.Data, src, len);
29654253
A
533 if(freeSrc) {
534 alloc.free(src);
535 }
bac41a7b
A
536 snaccObj.GoNext();
537 }
538}
539
540/* CE_GeneralNames --> snacc-style GeneralNames */
541/* GeneralNames from sm_x509cmn.h */
542GeneralNames *CL_cdsaGeneralNamesToSnacc(
543 CE_GeneralNames &cdsaObj)
544{
545 GeneralNames *snaccObj = new GeneralNames;
546 bool abortFlag = false; // true --> invalid incoming field
547 CssmAllocator &alloc = CssmAllocator::standard();
548
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) {
557 case GNT_OtherName:
558 /* OTHER_NAME, AsnOid */
559 if(currCdsaName->berEncoded) {
560 abortFlag = true;
561 break;
562 }
563 currSnaccName->choiceId = GeneralName::otherNameCid;
564 currSnaccName->otherName = new AsnOid(rawData, rawDataLen);
565 break;
566
567 case GNT_RFC822Name:
568 /* IA5String */
569 if(currCdsaName->berEncoded) {
570 abortFlag = true;
571 break;
572 }
573 currSnaccName->choiceId = GeneralName::rfc822NameCid;
574 currSnaccName->rfc822Name = new IA5String(rawData, rawDataLen);
575 break;
576 case GNT_DNSName:
577 /* IA5String */
578 if(currCdsaName->berEncoded) {
579 abortFlag = true;
580 break;
581 }
582 currSnaccName->choiceId = GeneralName::dNSNameCid;
583 currSnaccName->rfc822Name = new IA5String(rawData, rawDataLen);
584 break;
585
586 case GNT_X400Address:
587 /* ORAddress from sm_x411mtsas */
588 if(!currCdsaName->berEncoded) {
589 abortFlag = true;
590 break;
591 }
592 currSnaccName->choiceId = GeneralName::x400AddressCid;
593 currSnaccName->x400Address = new ORAddress;
594 try {
595 SC_decodeAsnObj(berData, *currSnaccName->x400Address);
596 }
597 catch(...) {
598 abortFlag = true;
599 }
600 break;
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
605 * CE_GeneralName).
606 */
607 if(!currCdsaName->berEncoded) {
608 abortFlag = true;
609 break;
610 }
611 currSnaccName->choiceId = GeneralName::directoryNameCid;
612 currSnaccName->directoryName = new Name;
613 try {
614 SC_decodeAsnObj(berData, *currSnaccName->directoryName);
615 }
616 catch(...) {
617 abortFlag = true;
618 }
619 break;
620
621 case GNT_EdiPartyName:
622 /* EDIPartyName from sm_x509cmn */
623 if(!currCdsaName->berEncoded) {
624 abortFlag = true;
625 break;
626 }
627 currSnaccName->choiceId = GeneralName::ediPartyNameCid;
628 currSnaccName->ediPartyName = new EDIPartyName;
629 try {
630 SC_decodeAsnObj(berData, *currSnaccName->ediPartyName);
631 }
632 catch(...) {
633 abortFlag = true;
634 }
635 break;
636
637 case GNT_URI:
638 /* IA5String */
639 if(currCdsaName->berEncoded) {
640 abortFlag = true;
641 break;
642 }
643 currSnaccName->choiceId = GeneralName::uniformResourceIdentifierCid;
644 currSnaccName->uniformResourceIdentifier =
645 new IA5String(rawData, rawDataLen);
646 break;
647
648 case GNT_IPAddress:
649 /* AsnOcts */
650 if(currCdsaName->berEncoded) {
651 abortFlag = true;
652 break;
653 }
654 currSnaccName->choiceId = GeneralName::iPAddressCid;
655 currSnaccName->iPAddress = new AsnOcts(rawData, rawDataLen);
656 break;
657 case GNT_RegisteredID:
658 /* AsnOid */
659 if(currCdsaName->berEncoded) {
660 abortFlag = true;
661 break;
662 }
663 currSnaccName->choiceId = GeneralName::registeredIDCid;
664 currSnaccName->registeredID = new AsnOid(rawData, rawDataLen);
665 break;
666 }
667 berData.release();
668 if(abortFlag) {
669 break;
670 }
671 }
672 if(abortFlag) {
673 delete snaccObj;
674 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
675 }
676 return snaccObj;
677}
678
679void CL_normalizeString(
680 char *strPtr,
681 int &strLen)
682{
683 char *pCh = strPtr; // working ptr
684 char *pD = pCh; // start of good string chars
685 char *pEos = pCh + strLen - 1;
686
687 if(strLen == 0) {
688 return;
689 }
690
691 /* adjust if Length included NULL terminator */
692 while(*pEos == 0) {
693 pEos--;
694 }
695
696 /* Remove trailing spaces */
697 while(isspace(*pEos)) {
698 pEos--;
699 }
700
701 /* Point to one past last non-space character */
702 pEos++;
703
704 /* upper case */
705 while(pCh < pEos) {
29654253
A
706 *pCh = toupper(*pCh);
707 pCh++;
bac41a7b
A
708 }
709
710 /* clean out whitespace */
711 /*
712 * 1. skip all leading whitespace
713 */
714 pCh = pD;
715 while(isspace(*pCh) && (pCh < pEos)) {
716 pCh++;
717 }
718
719 /*
720 * 2. eliminate multiple whitespace.
721 * pCh points to first non-white char.
722 * pD still points to start of string
723 */
724 char ch;
725 while(pCh < pEos) {
726 ch = *pCh++;
727 *pD++ = ch; // normal case
728 if( isspace(ch) ){
729 /* skip 'til next nonwhite */
730 while(isspace(*pCh) && (pCh < pEos)) {
731 pCh++;
732 }
733 }
734 };
735
736 strLen = pD - strPtr;
737}
738
739/*
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.
743 */
744void CL_normalizeX509Name(
745 Name &name,
746 CssmAllocator &alloc)
747{
748 RDNSequence *rdns = name.rDNSequence;
749 int numRdns = rdns->Count();
750 if((rdns == NULL) || (numRdns == 0)) {
751 /* not technically an error */
752 return;
753 }
754
755 rdns->SetCurrElmt(0);
756 for(int rdnDex=0; rdnDex<numRdns; rdnDex++) {
757 /* from sm_x501if */
758 RelativeDistinguishedName *rdn = rdns->Curr();
759 if(rdn == NULL) {
760 /* not sure how this can happen... */
761 dprintf1("clNormalizeX509Name: NULL rdn at index %d\n", rdnDex);
762 rdns->GoNext();
763 continue;
764 }
765 int numAttrs = rdn->Count();
766 if(numAttrs == 0) {
767 dprintf1("clNormalizeX509Name: zero numAttrs at index %d\n", rdnDex);
768 rdns->GoNext();
769 continue;
770 }
771
772 /* descend into array of attribute/values */
773 rdn->SetCurrElmt(0);
774 for(int attrDex=0; attrDex<numAttrs; attrDex++) {
775 /* from sm_x501if */
776 AttributeTypeAndDistinguishedValue *att = rdn->Curr();
777 if(att == NULL) {
778 /* not sure how this can happen... */
779 dprintf1("clNormalizeX509Name: NULL att at index %d\n", attrDex);
780 rdn->GoNext();
781 continue;
782 }
783
784 /*
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.
788 *
789 * (See e.g. the Thawte serverbasic cert, which has an email
790 * address in IA5String format.) In the IA5String case we skip the
791 * normalization.
792 *
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.
796 */
797 CSM_Buffer *cbuf = att->value.value;
798 DirectoryString dirStr;
799 char *cbufData = const_cast<char *>(cbuf->Access());
800 CssmData encodedStr(cbufData, cbuf->Length());
801
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 */
807 return;
808 }
809 try {
810 SC_decodeAsnObj(encodedStr, dirStr);
811 }
812 catch (...) {
813 /* can't normalize */
814 errorLog0("clNormalizeX509Name: malformed DirectoryString (1)\n");
815 return;
816 }
817
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);
822
823 /* set new AsnOcts data from normalized version, freeing old */
824 dirStr.teletexString->ReSet(strPtr, newLen);
825
826 /* encode result */
827 CssmAutoData normEncoded(alloc);
828 SC_encodeAsnObj(dirStr, normEncoded, newLen + 8);
829
830 /* set new AsnAny data */
831 cbuf->Set((char *)normEncoded.data(), normEncoded.length());
832
833 rdn->GoNext();
834 } /* for each attribute/value */
835 rdns->GoNext();
836 } /* for each RDN */
837}
838
29654253
A
839/*
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).
843 */
844CSSM_KEY_PTR CL_extractCSSMKey(
845 SubjectPublicKeyInfo &snaccKeyInfo,
846 CssmAllocator &alloc,
847 const DecodedCert *decodedCert) // optional
848{
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);
853 try {
854 hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
855 /* CspId blank */
856 hdr.BlobType = CSSM_KEYBLOB_RAW;
857 hdr.AlgorithmId = CL_snaccOidToCssmAlg(snaccKeyInfo.algorithm->algorithm);
858
859 /*
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
863 * to be correct.
864 */
865 switch(hdr.AlgorithmId) {
866 case CSSM_ALGID_RSA:
867 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
868 break;
869 case CSSM_ALGID_DSA:
870 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_FIPS186;
871 break;
872 case CSSM_ALGID_FEE:
873 /* CSSM_KEYBLOB_RAW_FORMAT_NONE --> DER encoded */
874 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
875 break;
876 default:
877 /* punt */
878 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
879 }
880 hdr.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
881
882 /* KeyUsage inferred from extensions */
883 if(decodedCert) {
884 hdr.KeyUsage = decodedCert->inferKeyUsage();
885 }
886 else {
887 hdr.KeyUsage = CSSM_KEYUSE_ANY;
888 }
889
890 /* start/end date unknown, leave zero */
891 hdr.WrapAlgorithmId = CSSM_ALGID_NONE;
892 hdr.WrapMode = CSSM_ALGMODE_NONE;
893
894 /*
895 * subjectPublicKeyInfo.subjectPublicKey (AsnBits) ==> KeyData
896 */
897 SC_asnBitsToCssmData(snaccKeyInfo.subjectPublicKey, keyData);
898 keyData.release();
899
900 /*
901 * LogicalKeySizeInBits - ask the CSP
902 */
903 CSSM_CSP_HANDLE cspHand = getGlobalCspHand(true);
904 CSSM_KEY_SIZE keySize;
905 CSSM_RETURN crtn;
906 crtn = CSSM_QueryKeySizeInBits(cspHand, CSSM_INVALID_HANDLE, cssmKey, &keySize);
907 if(crtn) {
908 CssmError::throwMe(crtn);
909 }
910 cssmKey->KeyHeader.LogicalKeySizeInBits =
911 keySize.LogicalKeySizeInBits;
912 }
913 catch (...) {
914 alloc.free(cssmKey);
915 throw;
916 }
917 return cssmKey;
918}
919
920void CL_freeCSSMKey(
921 CSSM_KEY_PTR cssmKey,
922 CssmAllocator &alloc,
923 bool freeTop)
924{
925 if(cssmKey == NULL) {
926 return;
927 }
928 alloc.free(cssmKey->KeyData.Data);
929 memset(cssmKey, 0, sizeof(CSSM_KEY));
930 if(freeTop) {
931 alloc.free(cssmKey);
932 }
933}
bac41a7b 934