2 * Copyright (c) 2002 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 * TPDatabase.cpp - TP's DL/DB access functions.
22 * Created 10/9/2002 by Doug Mitchell.
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"
41 * Given a DL/DB, look up cert by subject name. Subsequent
42 * certs can be found using the returned result handle.
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
51 CSSM_SELECTION_PREDICATE predicate
;
52 CSSM_DB_UNIQUE_RECORD_PTR record
= NULL
;
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;
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?
74 CSSM_DL_DataGetFirst(dlDb
,
77 NULL
, // don't fetch attributes
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.
90 TPCertInfo
*tpDbFindIssuerCert(
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
100 CSSM_HANDLE resultHand
;
102 CSSM_DL_DB_HANDLE dlDb
;
103 CSSM_DB_UNIQUE_RECORD_PTR record
;
104 TPCertInfo
*issuerCert
= NULL
;
107 partialIssuerKey
= false;
111 for(dbDex
=0; dbDex
<dbList
->NumHandles
; dbDex
++) {
112 dlDb
= dbList
->DLDBHandle
[dbDex
];
115 record
= tpCertLookup(dlDb
,
116 subjectItem
->issuerName(),
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)...
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
);
136 /* Does it verify the subject cert? */
137 CSSM_RETURN crtn
= subjectItem
->verifyWithIssuer(issuerCert
);
141 case CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE
:
142 partialIssuerKey
= true;
147 CSSM_DL_FreeUniqueRecord(dlDb
, record
);
150 * Verify fail. Continue searching this DB. Break on
151 * finding the holy grail or no more records found.
156 CSSM_RETURN crtn
= CSSM_DL_DataGetNext(dlDb
,
162 /* no more, done with this DB */
163 assert(cert
.Data
== NULL
);
166 assert(cert
.Data
!= NULL
);
168 /* found one - does it verify subject? */
169 issuerCert
= new TPCertInfo(clHand
, cspHand
, &cert
, TIC_CopyData
,
171 /* we're done with raw cert data */
172 tpFreeCssmData(alloc
, &cert
, CSSM_FALSE
);
176 /* FIXME - figure out allowExpire, etc. */
177 crtn
= subjectItem
->verifyWithIssuer(issuerCert
);
183 case CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE
:
184 partialIssuerKey
= true;
195 CSSM_DL_FreeUniqueRecord(dlDb
, record
);
197 } /* searching subsequent records */
198 } /* switch verify */
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
);
208 } /* tpCertLookup, i.e., CSSM_DL_DataGetFirst, succeeded */
210 assert(cert
.Data
== NULL
);
212 /* in any case, abort the query for this db */
213 CSSM_DL_DataAbortQuery(dlDb
, resultHand
);
215 } /* main loop searching dbList */
217 /* issuer not found */
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.
225 #define SEARCH_BY_DATE 1
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
235 CSSM_SELECTION_PREDICATE pred
[3];
236 CSSM_DB_UNIQUE_RECORD_PTR record
= NULL
;
237 char timeStr
[CSSM_TIME_STRLEN
+ 1];
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;
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
);
256 tpErrorLog("tpCrlLookup: Invalid VerifyTime string\n");
262 StLock
<Mutex
> _(tpTimeLock());
263 timeAtNowPlus(0, TIME_CSSM
, timeStr
);
266 timeData
.Data
= (uint8
*)timeStr
;
267 timeData
.Length
= CSSM_TIME_STRLEN
;
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;
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;
285 query
.RecordType
= CSSM_DL_DB_RECORD_X509_CRL
;
286 query
.Conjunctive
= CSSM_DB_AND
;
288 query
.NumSelectionPredicates
= 3;
290 query
.NumSelectionPredicates
= 1;
292 query
.SelectionPredicate
= pred
;
293 query
.QueryLimits
.TimeLimit
= 0; // FIXME - meaningful?
294 query
.QueryLimits
.SizeLimit
= 1; // FIXME - meaningful?
295 query
.QueryFlags
= 0; // FIXME - used?
297 CSSM_DL_DataGetFirst(dlDb
,
300 NULL
, // don't fetch attributes
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.
312 TPCrlInfo
*tpDbFindIssuerCrl(
313 TPCrlVerifyContext
&vfyCtx
,
314 const CSSM_DATA
&issuer
,
318 CSSM_HANDLE resultHand
;
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
;
329 for(dbDex
=0; dbDex
<dbList
->NumHandles
; dbDex
++) {
330 dlDb
= dbList
->DLDBHandle
[dbDex
];
333 record
= tpCrlLookup(dlDb
,
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)...
346 assert(crl
.Data
!= NULL
);
347 issuerCrl
= new TPCrlInfo(vfyCtx
.clHand
,
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
);
359 /* and we're done with the record */
360 CSSM_DL_FreeUniqueRecord(dlDb
, record
);
362 /* Does it verify with specified context? */
363 crtn
= issuerCrl
->verifyWithContext(vfyCtx
, &forCert
);
370 * Verify fail. Continue searching this DB. Break on
371 * finding the holy grail or no more records found.
376 crtn
= CSSM_DL_DataGetNext(dlDb
,
382 /* no more, done with this DB */
383 assert(crl
.Data
== NULL
);
386 assert(crl
.Data
!= NULL
);
388 /* found one - is it any good? */
389 issuerCrl
= new TPCrlInfo(vfyCtx
.clHand
,
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
);
401 CSSM_DL_FreeUniqueRecord(dlDb
, record
);
403 crtn
= issuerCrl
->verifyWithContext(vfyCtx
, &forCert
);
404 if(crtn
== CSSM_OK
) {
410 } /* searching subsequent records */
414 if(issuerCrl
!= NULL
) {
415 /* successful return */
416 CSSM_DL_DataAbortQuery(dlDb
, resultHand
);
417 tpDebug("tpDbFindIssuerCrl: found CRL record %p", record
);
420 } /* tpCrlLookup, i.e., CSSM_DL_DataGetFirst, succeeded */
422 assert(crl
.Data
== NULL
);
424 /* in any case, abort the query for this db */
425 CSSM_DL_DataAbortQuery(dlDb
, resultHand
);
427 } /* main loop searching dbList */
429 /* issuer not found */
434 * Update an existing DLDB to be CRL-capable.
436 static CSSM_RETURN
tpAddCrlSchema(
437 CSSM_DL_DB_HANDLE dlDbHand
)
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
);
449 * Search extensions for specified OID, assumed to have underlying
450 * value type of uint32; returns the value and true if found.
452 static bool tpSearchNumericExtension(
453 const CSSM_X509_EXTENSIONS
*extens
,
457 for(uint32 dex
=0; dex
<extens
->numberOfExtensions
; dex
++) {
458 const CSSM_X509_EXTENSION
*exten
= &extens
->extensions
[dex
];
459 if(!tpCompareOids(&exten
->extnId
, oid
)) {
462 if(exten
->format
!= CSSM_X509_DATAFORMAT_PAIR
) {
463 tpErrorLog("***Malformed CRL extension\n");
466 *val
= *((uint32
*)exten
->value
.parsedValue
);
473 * Store a CRL in a DLDB.
474 * We store the following attributes:
478 * PrintName (Inferred from issuer)
483 * CrlNumber (if present)
484 * DeltaCrlNumber (if present)
486 #define MAX_CRL_ATTRS 9
488 CSSM_RETURN
tpDbStoreCrl(
490 CSSM_DL_DB_HANDLE
&dlDbHand
)
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
;
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];
507 uint32 deltaCrlNumber
;
508 CSSM_DATA crlNumberData
;
509 CSSM_DATA deltaCrlNumberData
;
510 bool crlNumberPresent
= false;
511 bool deltaCrlPresent
= false;
513 tbsCrl
= &(crl
.x509Crl()->tbsCertList
);
515 /* CrlType inferred from version */
516 if(tbsCrl
->version
.Length
== 0) {
517 /* should never happen... */
518 crlType
= CSSM_CRL_TYPE_X_509v1
;
521 uint8 vers
= tbsCrl
->version
.Data
[tbsCrl
->version
.Length
- 1];
524 crlType
= CSSM_CRL_TYPE_X_509v1
;
527 crlType
= CSSM_CRL_TYPE_X_509v2
;
530 tpErrorLog("***Unknown version in CRL (%u)\n", vers
);
531 crlType
= CSSM_CRL_TYPE_X_509v1
;
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
);
541 /* printName inferred from issuer */
543 const CSSM_DATA
*printNamePtr
;
544 printNamePtr
= SecInferLabelFromX509Name(&tbsCrl
->issuer
);
546 printName
= *(const_cast<CSSM_DATA
*>(printNamePtr
));
549 printName
.Data
= (uint8
*)"X509 CRL";
550 printName
.Length
= 8;
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
,
558 tpErrorLog("***Badly formatted thisUpdate\n");
561 thisUpdateData
.Data
= (uint8
*)thisUpdate
;
562 thisUpdateData
.Length
= CSSM_TIME_STRLEN
;
564 if(tbsCrl
->nextUpdate
.time
.Data
!= NULL
) {
565 rtn
= tpTimeToCssmTimestring((const char *)tbsCrl
->nextUpdate
.time
.Data
,
566 tbsCrl
->nextUpdate
.time
.Length
,
569 tpErrorLog("***Badly formatted nextUpdate\n");
572 nextUpdateData
.Data
= (uint8
*)nextUpdate
;
573 nextUpdateData
.Length
= CSSM_TIME_STRLEN
;
578 * NextUpdate not present; fake it by using "virtual end of time"
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
;
586 /* optional CrlNumber and DeltaCrlNumber */
587 if(tpSearchNumericExtension(&tbsCrl
->extensions
,
590 crlNumberData
.Data
= (uint8
*)&crlNumber
;
591 crlNumberData
.Length
= sizeof(uint32
);
592 crlNumberPresent
= true;
594 if(tpSearchNumericExtension(&tbsCrl
->extensions
,
595 &CSSMOID_DeltaCrlIndicator
,
597 deltaCrlNumberData
.Data
= (uint8
*)&deltaCrlNumber
;
598 deltaCrlNumberData
.Length
= sizeof(uint32
);
599 deltaCrlPresent
= true;
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
;
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
;
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
;
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());
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
;
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
;
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) {
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;
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
;
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
;
675 recordAttrs
.DataRecordType
= CSSM_DL_DB_RECORD_X509_CRL
;
676 recordAttrs
.SemanticInformation
= 0;
677 recordAttrs
.NumberOfAttributes
= attr
- attrs
;
678 recordAttrs
.AttributeData
= attrs
;
680 crtn
= CSSM_DL_DataInsert(dlDbHand
,
681 CSSM_DL_DB_RECORD_X509_CRL
,
685 if(crtn
== CSSMERR_DL_INVALID_RECORDTYPE
) {
686 /* gross hack of inserting this "new" schema that Keychain
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
,
699 tpErrorLog("CSSM_DL_DataInsert: %s", cssmErrorString(crtn
).c_str());
702 CSSM_DL_FreeUniqueRecord(dlDbHand
, recordPtr
);