]> git.saurik.com Git - apple/security.git/blob - AppleX509TP/TPDatabase.cpp
Security-177.tar.gz
[apple/security.git] / AppleX509TP / TPDatabase.cpp
1 /*
2 * Copyright (c) 2002 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 * TPDatabase.cpp - TP's DL/DB access functions.
21 *
22 * Created 10/9/2002 by Doug Mitchell.
23 */
24
25 #include <Security/cssmtype.h>
26 #include <Security/cssmapi.h>
27 #include <Security/Schema.h> /* private API */
28 #include <Security/SecCertificatePriv.h> /* private SecInferLabelFromX509Name() */
29 #include <Security/oidscert.h>
30 #include <Security/cssmerrno.h>
31 #include "TPDatabase.h"
32 #include "tpdebugging.h"
33 #include "certGroupUtils.h"
34 #include "TPCertInfo.h"
35 #include "TPCrlInfo.h"
36 #include "tpCrlVerify.h"
37 #include "tpTime.h"
38
39
40 /*
41 * Given a DL/DB, look up cert by subject name. Subsequent
42 * certs can be found using the returned result handle.
43 */
44 static CSSM_DB_UNIQUE_RECORD_PTR tpCertLookup(
45 CSSM_DL_DB_HANDLE dlDb,
46 const CSSM_DATA *subjectName, // DER-encoded
47 CSSM_HANDLE_PTR resultHand, // RETURNED
48 CSSM_DATA_PTR cert) // RETURNED
49 {
50 CSSM_QUERY query;
51 CSSM_SELECTION_PREDICATE predicate;
52 CSSM_DB_UNIQUE_RECORD_PTR record = NULL;
53
54 cert->Data = NULL;
55 cert->Length = 0;
56
57 /* SWAG until cert schema nailed down */
58 predicate.DbOperator = CSSM_DB_EQUAL;
59 predicate.Attribute.Info.AttributeNameFormat =
60 CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
61 predicate.Attribute.Info.Label.AttributeName = "Subject";
62 predicate.Attribute.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
63 predicate.Attribute.Value = const_cast<CSSM_DATA_PTR>(subjectName);
64 predicate.Attribute.NumberOfValues = 1;
65
66 query.RecordType = CSSM_DL_DB_RECORD_X509_CERTIFICATE;
67 query.Conjunctive = CSSM_DB_NONE;
68 query.NumSelectionPredicates = 1;
69 query.SelectionPredicate = &predicate;
70 query.QueryLimits.TimeLimit = 0; // FIXME - meaningful?
71 query.QueryLimits.SizeLimit = 1; // FIXME - meaningful?
72 query.QueryFlags = 0; // FIXME - used?
73
74 CSSM_DL_DataGetFirst(dlDb,
75 &query,
76 resultHand,
77 NULL, // don't fetch attributes
78 cert,
79 &record);
80 return record;
81 }
82
83 /*
84 * Search a list of DBs for a cert which verifies specified subject item.
85 * Just a boolean return - we found it, or not. If we did, we return
86 * TPCertInfo associated with the raw cert.
87 * A true partialIssuerKey on return indicates that caller must deal
88 * with partial public key processing later.
89 */
90 TPCertInfo *tpDbFindIssuerCert(
91 CssmAllocator &alloc,
92 CSSM_CL_HANDLE clHand,
93 CSSM_CSP_HANDLE cspHand,
94 const TPClItemInfo *subjectItem,
95 const CSSM_DL_DB_LIST *dbList,
96 const char *verifyTime, // may be NULL
97 bool &partialIssuerKey) // RETURNED
98 {
99 uint32 dbDex;
100 CSSM_HANDLE resultHand;
101 CSSM_DATA cert;
102 CSSM_DL_DB_HANDLE dlDb;
103 CSSM_DB_UNIQUE_RECORD_PTR record;
104 TPCertInfo *issuerCert = NULL;
105 bool foundIt;
106
107 partialIssuerKey = false;
108 if(dbList == NULL) {
109 return NULL;
110 }
111 for(dbDex=0; dbDex<dbList->NumHandles; dbDex++) {
112 dlDb = dbList->DLDBHandle[dbDex];
113 cert.Data = NULL;
114 cert.Length = 0;
115 record = tpCertLookup(dlDb,
116 subjectItem->issuerName(),
117 &resultHand,
118 &cert);
119 /* remember we have to:
120 * -- abort this query regardless, and
121 * -- free the CSSM_DATA cert regardless, and
122 * -- free the unique record if we don't use it
123 * (by placing it in issuerCert)...
124 */
125 if(record != NULL) {
126 /* Found one */
127 assert(cert.Data != NULL);
128 issuerCert = new TPCertInfo(clHand, cspHand, &cert, TIC_CopyData, verifyTime);
129 /* we're done with raw cert data */
130 /* FIXME this assumes that alloc is the same as the
131 * allocator associated with DlDB...OK? */
132 tpFreeCssmData(alloc, &cert, CSSM_FALSE);
133 cert.Data = NULL;
134 cert.Length = 0;
135
136 /* Does it verify the subject cert? */
137 CSSM_RETURN crtn = subjectItem->verifyWithIssuer(issuerCert);
138 switch(crtn) {
139 case CSSM_OK:
140 break;
141 case CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE:
142 partialIssuerKey = true;
143 break;
144 default:
145 delete issuerCert;
146 issuerCert = NULL;
147 CSSM_DL_FreeUniqueRecord(dlDb, record);
148
149 /*
150 * Verify fail. Continue searching this DB. Break on
151 * finding the holy grail or no more records found.
152 */
153 for(;;) {
154 cert.Data = NULL;
155 cert.Length = 0;
156 CSSM_RETURN crtn = CSSM_DL_DataGetNext(dlDb,
157 resultHand,
158 NULL, // no attrs
159 &cert,
160 &record);
161 if(crtn) {
162 /* no more, done with this DB */
163 assert(cert.Data == NULL);
164 break;
165 }
166 assert(cert.Data != NULL);
167
168 /* found one - does it verify subject? */
169 issuerCert = new TPCertInfo(clHand, cspHand, &cert, TIC_CopyData,
170 verifyTime);
171 /* we're done with raw cert data */
172 tpFreeCssmData(alloc, &cert, CSSM_FALSE);
173 cert.Data = NULL;
174 cert.Length = 0;
175
176 /* FIXME - figure out allowExpire, etc. */
177 crtn = subjectItem->verifyWithIssuer(issuerCert);
178 foundIt = false;
179 switch(crtn) {
180 case CSSM_OK:
181 foundIt = true;
182 break;
183 case CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE:
184 partialIssuerKey = true;
185 foundIt = true;
186 break;
187 default:
188 break;
189 }
190 if(foundIt) {
191 /* yes! */
192 break;
193 }
194 delete issuerCert;
195 CSSM_DL_FreeUniqueRecord(dlDb, record);
196 issuerCert = NULL;
197 } /* searching subsequent records */
198 } /* switch verify */
199
200 if(issuerCert != NULL) {
201 /* successful return */
202 tpDebug("tpDbFindIssuer: found cert record %p", record);
203 CSSM_DL_DataAbortQuery(dlDb, resultHand);
204 issuerCert->dlDbHandle(dlDb);
205 issuerCert->uniqueRecord(record);
206 return issuerCert;
207 }
208 } /* tpCertLookup, i.e., CSSM_DL_DataGetFirst, succeeded */
209 else {
210 assert(cert.Data == NULL);
211 }
212 /* in any case, abort the query for this db */
213 CSSM_DL_DataAbortQuery(dlDb, resultHand);
214
215 } /* main loop searching dbList */
216
217 /* issuer not found */
218 return NULL;
219 }
220
221 /*
222 * Given a DL/DB, look up CRL by issuer name and validity time.
223 * Subsequent CRLs can be found using the returned result handle.
224 */
225 #define SEARCH_BY_DATE 1
226
227 static CSSM_DB_UNIQUE_RECORD_PTR tpCrlLookup(
228 CSSM_DL_DB_HANDLE dlDb,
229 const CSSM_DATA *issuerName, // DER-encoded
230 CSSM_TIMESTRING verifyTime, // may be NULL, implies "now"
231 CSSM_HANDLE_PTR resultHand, // RETURNED
232 CSSM_DATA_PTR crl) // RETURNED
233 {
234 CSSM_QUERY query;
235 CSSM_SELECTION_PREDICATE pred[3];
236 CSSM_DB_UNIQUE_RECORD_PTR record = NULL;
237 char timeStr[CSSM_TIME_STRLEN + 1];
238
239 crl->Data = NULL;
240 crl->Length = 0;
241
242 /* Three predicates...first, the issuer name */
243 pred[0].DbOperator = CSSM_DB_EQUAL;
244 pred[0].Attribute.Info.AttributeNameFormat =
245 CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
246 pred[0].Attribute.Info.Label.AttributeName = "Issuer";
247 pred[0].Attribute.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
248 pred[0].Attribute.Value = const_cast<CSSM_DATA_PTR>(issuerName);
249 pred[0].Attribute.NumberOfValues = 1;
250
251 /* now before/after. Cook up an appropriate time string. */
252 if(verifyTime != NULL) {
253 /* Caller spec'd tolerate any format */
254 int rtn = tpTimeToCssmTimestring(verifyTime, strlen(verifyTime), timeStr);
255 if(rtn) {
256 tpErrorLog("tpCrlLookup: Invalid VerifyTime string\n");
257 return NULL;
258 }
259 }
260 else {
261 /* right now */
262 StLock<Mutex> _(tpTimeLock());
263 timeAtNowPlus(0, TIME_CSSM, timeStr);
264 }
265 CSSM_DATA timeData;
266 timeData.Data = (uint8 *)timeStr;
267 timeData.Length = CSSM_TIME_STRLEN;
268
269 #if SEARCH_BY_DATE
270 pred[1].DbOperator = CSSM_DB_LESS_THAN;
271 pred[1].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
272 pred[1].Attribute.Info.Label.AttributeName = "NextUpdate";
273 pred[1].Attribute.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
274 pred[1].Attribute.Value = &timeData;
275 pred[1].Attribute.NumberOfValues = 1;
276
277 pred[2].DbOperator = CSSM_DB_GREATER_THAN;
278 pred[2].Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
279 pred[2].Attribute.Info.Label.AttributeName = "ThisUpdate";
280 pred[2].Attribute.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
281 pred[2].Attribute.Value = &timeData;
282 pred[2].Attribute.NumberOfValues = 1;
283 #endif
284
285 query.RecordType = CSSM_DL_DB_RECORD_X509_CRL;
286 query.Conjunctive = CSSM_DB_AND;
287 #if SEARCH_BY_DATE
288 query.NumSelectionPredicates = 3;
289 #else
290 query.NumSelectionPredicates = 1;
291 #endif
292 query.SelectionPredicate = pred;
293 query.QueryLimits.TimeLimit = 0; // FIXME - meaningful?
294 query.QueryLimits.SizeLimit = 1; // FIXME - meaningful?
295 query.QueryFlags = 0; // FIXME - used?
296
297 CSSM_DL_DataGetFirst(dlDb,
298 &query,
299 resultHand,
300 NULL, // don't fetch attributes
301 crl,
302 &record);
303 return record;
304 }
305
306 /*
307 * Search a list of DBs for a CRL from the specified issuer and (optional)
308 * TPCrlVerifyContext.verifyTime.
309 * Just a boolean return - we found it, or not. If we did, we return a
310 * TPCrlInfo which has been verified with the specified TPCrlVerifyContext.
311 */
312 TPCrlInfo *tpDbFindIssuerCrl(
313 TPCrlVerifyContext &vfyCtx,
314 const CSSM_DATA &issuer,
315 TPCertInfo &forCert)
316 {
317 uint32 dbDex;
318 CSSM_HANDLE resultHand;
319 CSSM_DATA crl;
320 CSSM_DL_DB_HANDLE dlDb;
321 CSSM_DB_UNIQUE_RECORD_PTR record;
322 TPCrlInfo *issuerCrl = NULL;
323 CSSM_DL_DB_LIST_PTR dbList = vfyCtx.dbList;
324 CSSM_RETURN crtn;
325
326 if(dbList == NULL) {
327 return NULL;
328 }
329 for(dbDex=0; dbDex<dbList->NumHandles; dbDex++) {
330 dlDb = dbList->DLDBHandle[dbDex];
331 crl.Data = NULL;
332 crl.Length = 0;
333 record = tpCrlLookup(dlDb,
334 &issuer,
335 vfyCtx.verifyTime,
336 &resultHand,
337 &crl);
338 /* remember we have to:
339 * -- abort this query regardless, and
340 * -- free the CSSM_DATA crl regardless, and
341 * -- free the unique record if we don't use it
342 * (by placing it in issuerCert)...
343 */
344 if(record != NULL) {
345 /* Found one */
346 assert(crl.Data != NULL);
347 issuerCrl = new TPCrlInfo(vfyCtx.clHand,
348 vfyCtx.cspHand,
349 &crl,
350 TIC_CopyData,
351 vfyCtx.verifyTime);
352 /* we're done with raw CRL data */
353 /* FIXME this assumes that vfyCtx.alloc is the same as the
354 * allocator associated with DlDB...OK? */
355 tpFreeCssmData(vfyCtx.alloc, &crl, CSSM_FALSE);
356 crl.Data = NULL;
357 crl.Length = 0;
358
359 /* and we're done with the record */
360 CSSM_DL_FreeUniqueRecord(dlDb, record);
361
362 /* Does it verify with specified context? */
363 crtn = issuerCrl->verifyWithContext(vfyCtx, &forCert);
364 if(crtn) {
365
366 delete issuerCrl;
367 issuerCrl = NULL;
368
369 /*
370 * Verify fail. Continue searching this DB. Break on
371 * finding the holy grail or no more records found.
372 */
373 for(;;) {
374 crl.Data = NULL;
375 crl.Length = 0;
376 crtn = CSSM_DL_DataGetNext(dlDb,
377 resultHand,
378 NULL, // no attrs
379 &crl,
380 &record);
381 if(crtn) {
382 /* no more, done with this DB */
383 assert(crl.Data == NULL);
384 break;
385 }
386 assert(crl.Data != NULL);
387
388 /* found one - is it any good? */
389 issuerCrl = new TPCrlInfo(vfyCtx.clHand,
390 vfyCtx.cspHand,
391 &crl,
392 TIC_CopyData,
393 vfyCtx.verifyTime);
394 /* we're done with raw CRL data */
395 /* FIXME this assumes that vfyCtx.alloc is the same as the
396 * allocator associated with DlDB...OK? */
397 tpFreeCssmData(vfyCtx.alloc, &crl, CSSM_FALSE);
398 crl.Data = NULL;
399 crl.Length = 0;
400
401 CSSM_DL_FreeUniqueRecord(dlDb, record);
402
403 crtn = issuerCrl->verifyWithContext(vfyCtx, &forCert);
404 if(crtn == CSSM_OK) {
405 /* yes! */
406 break;
407 }
408 delete issuerCrl;
409 issuerCrl = NULL;
410 } /* searching subsequent records */
411 } /* verify fail */
412 /* else success! */
413
414 if(issuerCrl != NULL) {
415 /* successful return */
416 CSSM_DL_DataAbortQuery(dlDb, resultHand);
417 tpDebug("tpDbFindIssuerCrl: found CRL record %p", record);
418 return issuerCrl;
419 }
420 } /* tpCrlLookup, i.e., CSSM_DL_DataGetFirst, succeeded */
421 else {
422 assert(crl.Data == NULL);
423 }
424 /* in any case, abort the query for this db */
425 CSSM_DL_DataAbortQuery(dlDb, resultHand);
426
427 } /* main loop searching dbList */
428
429 /* issuer not found */
430 return NULL;
431 }
432
433 /*
434 * Update an existing DLDB to be CRL-capable.
435 */
436 static CSSM_RETURN tpAddCrlSchema(
437 CSSM_DL_DB_HANDLE dlDbHand)
438 {
439 return CSSM_DL_CreateRelation(dlDbHand,
440 CSSM_DL_DB_RECORD_X509_CRL,
441 "CSSM_DL_DB_RECORD_X509_CRL",
442 Security::KeychainCore::Schema::X509CrlSchemaAttributeCount,
443 Security::KeychainCore::Schema::X509CrlSchemaAttributeList,
444 Security::KeychainCore::Schema::X509CrlSchemaIndexCount,
445 Security::KeychainCore::Schema::X509CrlSchemaIndexList);
446 }
447
448 /*
449 * Search extensions for specified OID, assumed to have underlying
450 * value type of uint32; returns the value and true if found.
451 */
452 static bool tpSearchNumericExtension(
453 const CSSM_X509_EXTENSIONS *extens,
454 const CSSM_OID *oid,
455 uint32 *val)
456 {
457 for(uint32 dex=0; dex<extens->numberOfExtensions; dex++) {
458 const CSSM_X509_EXTENSION *exten = &extens->extensions[dex];
459 if(!tpCompareOids(&exten->extnId, oid)) {
460 continue;
461 }
462 if(exten->format != CSSM_X509_DATAFORMAT_PAIR) {
463 tpErrorLog("***Malformed CRL extension\n");
464 continue;
465 }
466 *val = *((uint32 *)exten->value.parsedValue);
467 return true;
468 }
469 return false;
470 }
471
472 /*
473 * Store a CRL in a DLDB.
474 * We store the following attributes:
475 *
476 * CrlType
477 * CrlEncoding
478 * PrintName (Inferred from issuer)
479 * Issuer
480 * ThisUpdate
481 * NextUpdate
482 * URI (if present)
483 * CrlNumber (if present)
484 * DeltaCrlNumber (if present)
485 */
486 #define MAX_CRL_ATTRS 9
487
488 CSSM_RETURN tpDbStoreCrl(
489 TPCrlInfo &crl,
490 CSSM_DL_DB_HANDLE &dlDbHand)
491 {
492 CSSM_DB_ATTRIBUTE_DATA attrs[MAX_CRL_ATTRS];
493 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs;
494 CSSM_DB_ATTRIBUTE_DATA_PTR attr = &attrs[0];
495 CSSM_DATA crlTypeData;
496 CSSM_DATA crlEncData;
497 CSSM_RETURN crtn;
498 CSSM_DB_UNIQUE_RECORD_PTR recordPtr;
499 CSSM_CRL_ENCODING crlEnc = CSSM_CRL_ENCODING_DER;
500 const CSSM_X509_TBS_CERTLIST *tbsCrl;
501 CSSM_CRL_TYPE crlType;
502 CSSM_DATA thisUpdateData = {0, NULL};
503 CSSM_DATA nextUpdateData = {0, NULL};
504 char thisUpdate[CSSM_TIME_STRLEN+1];
505 char nextUpdate[CSSM_TIME_STRLEN+1];
506 uint32 crlNumber;
507 uint32 deltaCrlNumber;
508 CSSM_DATA crlNumberData;
509 CSSM_DATA deltaCrlNumberData;
510 bool crlNumberPresent = false;
511 bool deltaCrlPresent = false;
512
513 tbsCrl = &(crl.x509Crl()->tbsCertList);
514
515 /* CrlType inferred from version */
516 if(tbsCrl->version.Length == 0) {
517 /* should never happen... */
518 crlType = CSSM_CRL_TYPE_X_509v1;
519 }
520 else {
521 uint8 vers = tbsCrl->version.Data[tbsCrl->version.Length - 1];
522 switch(vers) {
523 case 0:
524 crlType = CSSM_CRL_TYPE_X_509v1;
525 break;
526 case 1:
527 crlType = CSSM_CRL_TYPE_X_509v2;
528 break;
529 default:
530 tpErrorLog("***Unknown version in CRL (%u)\n", vers);
531 crlType = CSSM_CRL_TYPE_X_509v1;
532 break;
533 }
534 }
535 crlTypeData.Data = (uint8 *)&crlType;
536 crlTypeData.Length = sizeof(CSSM_CRL_TYPE);
537 /* encoding more-or-less assumed here */
538 crlEncData.Data = (uint8 *)&crlEnc;
539 crlEncData.Length = sizeof(CSSM_CRL_ENCODING);
540
541 /* printName inferred from issuer */
542 CSSM_DATA printName;
543 const CSSM_DATA *printNamePtr;
544 printNamePtr = SecInferLabelFromX509Name(&tbsCrl->issuer);
545 if(printNamePtr) {
546 printName = *(const_cast<CSSM_DATA *>(printNamePtr));
547 }
548 else {
549 printName.Data = (uint8 *)"X509 CRL";
550 printName.Length = 8;
551 }
552
553 /* cook up CSSM_TIMESTRING versions of this/next update */
554 int rtn = tpTimeToCssmTimestring((const char *)tbsCrl->thisUpdate.time.Data,
555 tbsCrl->thisUpdate.time.Length,
556 thisUpdate);
557 if(rtn) {
558 tpErrorLog("***Badly formatted thisUpdate\n");
559 }
560 else {
561 thisUpdateData.Data = (uint8 *)thisUpdate;
562 thisUpdateData.Length = CSSM_TIME_STRLEN;
563 }
564 if(tbsCrl->nextUpdate.time.Data != NULL) {
565 rtn = tpTimeToCssmTimestring((const char *)tbsCrl->nextUpdate.time.Data,
566 tbsCrl->nextUpdate.time.Length,
567 nextUpdate);
568 if(rtn) {
569 tpErrorLog("***Badly formatted nextUpdate\n");
570 }
571 else {
572 nextUpdateData.Data = (uint8 *)nextUpdate;
573 nextUpdateData.Length = CSSM_TIME_STRLEN;
574 }
575 }
576 else {
577 /*
578 * NextUpdate not present; fake it by using "virtual end of time"
579 */
580 tpTimeToCssmTimestring(CSSM_APPLE_CRL_END_OF_TIME,
581 strlen(CSSM_APPLE_CRL_END_OF_TIME), nextUpdate);
582 nextUpdateData.Data = (uint8 *)nextUpdate;
583 nextUpdateData.Length = CSSM_TIME_STRLEN;
584 }
585
586 /* optional CrlNumber and DeltaCrlNumber */
587 if(tpSearchNumericExtension(&tbsCrl->extensions,
588 &CSSMOID_CrlNumber,
589 &crlNumber)) {
590 crlNumberData.Data = (uint8 *)&crlNumber;
591 crlNumberData.Length = sizeof(uint32);
592 crlNumberPresent = true;
593 }
594 if(tpSearchNumericExtension(&tbsCrl->extensions,
595 &CSSMOID_DeltaCrlIndicator,
596 &deltaCrlNumber)) {
597 deltaCrlNumberData.Data = (uint8 *)&deltaCrlNumber;
598 deltaCrlNumberData.Length = sizeof(uint32);
599 deltaCrlPresent = true;
600 }
601
602 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
603 attr->Info.Label.AttributeName = "CrlType";
604 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_UINT32;
605 attr->NumberOfValues = 1;
606 attr->Value = &crlTypeData;
607 attr++;
608
609 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
610 attr->Info.Label.AttributeName = "CrlEncoding";
611 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_UINT32;
612 attr->NumberOfValues = 1;
613 attr->Value = &crlEncData;
614 attr++;
615
616 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
617 attr->Info.Label.AttributeName = "PrintName";
618 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
619 attr->NumberOfValues = 1;
620 attr->Value = &printName;
621 attr++;
622
623 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
624 attr->Info.Label.AttributeName = "Issuer";
625 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
626 attr->NumberOfValues = 1;
627 attr->Value = const_cast<CSSM_DATA *>(crl.issuerName());
628 attr++;
629
630 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
631 attr->Info.Label.AttributeName = "ThisUpdate";
632 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
633 attr->NumberOfValues = 1;
634 attr->Value = &thisUpdateData;
635 attr++;
636
637 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
638 attr->Info.Label.AttributeName = "NextUpdate";
639 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
640 attr->NumberOfValues = 1;
641 attr->Value = &nextUpdateData;
642 attr++;
643
644 /* now the optional attributes */
645 CSSM_DATA uri = *crl.uri();
646 if(uri.Data != NULL) {
647 /* ensure URI string does not contain NULL */
648 if(uri.Data[uri.Length - 1] == 0) {
649 uri.Length--;
650 }
651 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
652 attr->Info.Label.AttributeName = "URI";
653 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
654 attr->NumberOfValues = 1;
655 attr->Value = &uri;
656 attr++;
657 }
658 if(crlNumberPresent) {
659 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
660 attr->Info.Label.AttributeName = "CrlNumber";
661 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_UINT32;
662 attr->NumberOfValues = 1;
663 attr->Value = &crlNumberData;
664 attr++;
665 }
666 if(deltaCrlPresent) {
667 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
668 attr->Info.Label.AttributeName = "DeltaCrlNumber";
669 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_UINT32;
670 attr->NumberOfValues = 1;
671 attr->Value = &deltaCrlNumberData;
672 attr++;
673 }
674
675 recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_X509_CRL;
676 recordAttrs.SemanticInformation = 0;
677 recordAttrs.NumberOfAttributes = attr - attrs;
678 recordAttrs.AttributeData = attrs;
679
680 crtn = CSSM_DL_DataInsert(dlDbHand,
681 CSSM_DL_DB_RECORD_X509_CRL,
682 &recordAttrs,
683 crl.itemData(),
684 &recordPtr);
685 if(crtn == CSSMERR_DL_INVALID_RECORDTYPE) {
686 /* gross hack of inserting this "new" schema that Keychain
687 * didn't specify */
688 crtn = tpAddCrlSchema(dlDbHand);
689 if(crtn == CSSM_OK) {
690 /* Retry with a fully capable DLDB */
691 crtn = CSSM_DL_DataInsert(dlDbHand,
692 CSSM_DL_DB_RECORD_X509_CRL,
693 &recordAttrs,
694 crl.itemData(),
695 &recordPtr);
696 }
697 }
698 if(crtn) {
699 tpErrorLog("CSSM_DL_DataInsert: %s", cssmErrorString(crtn).c_str());
700 }
701 else {
702 CSSM_DL_FreeUniqueRecord(dlDbHand, recordPtr);
703 }
704
705 return crtn;
706 }