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 * TPCertInfo.h - TP's private certificate info classes
22 * Written 10/23/2000 by Doug Mitchell.
25 #include "TPCertInfo.h"
26 #include "tpdebugging.h"
28 #include "certGroupUtils.h"
29 #include <Security/cssmapi.h>
30 #include <Security/x509defs.h>
31 #include <Security/oidscert.h>
32 #include <Security/oidsalg.h>
33 #include <string.h> /* for memcmp */
34 #include <Security/threading.h> /* for Mutex */
35 #include <Security/globalizer.h>
36 #include <Security/debugging.h>
38 #define tpTimeDbg(args...) debug("tpTime", ## args)
41 * No default constructor - this is the only way.
42 * This caches the cert and fetches subjectName and issuerName
43 * to ensure the incoming certData is well-constructed.
45 TPCertInfo::TPCertInfo(
46 const CSSM_DATA
*certData
,
47 CSSM_CL_HANDLE clHand
,
48 bool copyCertData
) : // true: we copy, we free
49 // false - caller owns
51 mCacheHand(CSSM_INVALID_HANDLE
),
58 mCertData
= tpMallocCopyCssmData(CssmAllocator::standard(), certData
);
61 mCertData
= const_cast<CSSM_DATA
*>(certData
);
63 mWeOwnTheData
= copyCertData
;
67 crtn
= CSSM_CL_CertCache(clHand
, mCertData
, &mCacheHand
);
70 CssmError::throwMe(crtn
);
73 /* fetch subject name */
74 crtn
= fetchField(&CSSMOID_X509V1SubjectName
, &mSubjectName
);
78 CssmError::throwMe(crtn
);
81 /* fetch issuer name */
82 crtn
= fetchField(&CSSMOID_X509V1IssuerName
, &mIssuerName
);
86 CssmError::throwMe(crtn
);
90 /* frees mSubjectName, mIssuerName, mCacheHand via mClHand */
91 TPCertInfo::~TPCertInfo()
96 void TPCertInfo::releaseResources()
98 if(mWeOwnTheData
&& (mCertData
!= NULL
)) {
99 tpFreeCssmData(CssmAllocator::standard(), mCertData
, CSSM_TRUE
);
102 freeField(&CSSMOID_X509V1SubjectName
, mSubjectName
);
105 freeField(&CSSMOID_X509V1IssuerName
, mIssuerName
);
107 if(mCacheHand
!= CSSM_INVALID_HANDLE
) {
108 CSSM_CL_CertAbortCache(mClHand
, mCacheHand
);
112 /* fetch arbitrary field from cached cert */
113 CSSM_RETURN
TPCertInfo::fetchField(
114 const CSSM_OID
*fieldOid
,
115 CSSM_DATA_PTR
*fieldData
) // mallocd by CL and RETURNED
119 uint32 NumberOfFields
= 0;
120 CSSM_HANDLE resultHand
= 0;
123 crtn
= CSSM_CL_CertGetFirstCachedFieldValue(
133 if(NumberOfFields
!= 1) {
134 errorLog1("TPCertInfo::fetchField: numFields %d, expected 1\n",
135 (int)NumberOfFields
);
137 CSSM_CL_CertAbortQuery(mClHand
, resultHand
);
141 /* free arbitrary field obtained from fetchField() */
142 CSSM_RETURN
TPCertInfo::freeField(
143 const CSSM_OID
*fieldOid
,
144 CSSM_DATA_PTR fieldData
)
146 return CSSM_CL_FreeFieldValue(mClHand
, fieldOid
, fieldData
);
151 CSSM_CL_HANDLE
TPCertInfo::clHand()
156 CSSM_HANDLE
TPCertInfo::cacheHand()
161 const CSSM_DATA
*TPCertInfo::certData()
163 CASSERT(mCertData
!= NULL
);
167 const CSSM_DATA
*TPCertInfo::subjectName()
169 CASSERT(mSubjectName
!= NULL
);
173 const CSSM_DATA
*TPCertInfo::issuerName()
175 CASSERT(mIssuerName
!= NULL
);
179 bool TPCertInfo::isSelfSigned() // i.e., subject == issuer
181 return tpCompareCssmData(mSubjectName
, mIssuerName
) ? true : false;
185 * Verify validity (not before/after). Returns
186 * CSSMERR_TP_CERT_NOT_VALID_YET
187 * CSSMERR_TP_CERT_EXPIRED
189 * CSSMERR_TP_INVALID_CERT_POINTER, other "bogus cert" errors
191 * We use some stdlib time calls over in tpTime.c; the stdlib function
192 * gmtime() is not thread-safe, so we do the protection here. Note that
193 * this makes *our* calls to gmtime() thread-safe, but if the app has
194 * other threads which are also calling gmtime, we're out of luck.
196 static ModuleNexus
<Mutex
> tpTimeLock
;
198 CSSM_RETURN
TPCertInfo::isCurrent(
199 CSSM_BOOL allowExpired
)
201 CSSM_DATA_PTR notBeforeField
= NULL
;
202 CSSM_DATA_PTR notAfterField
= NULL
;
203 CSSM_RETURN crtn
= CSSM_OK
;
205 CASSERT(mCacheHand
!= CSSM_INVALID_HANDLE
);
206 crtn
= fetchField(&CSSMOID_X509V1ValidityNotBefore
, ¬BeforeField
);
208 errorLog0("TPCertInfo::isCurrent: GetField error");
214 StLock
<Mutex
> _(tpTimeLock());
218 CSSM_X509_TIME
*xNotBefore
= (CSSM_X509_TIME
*)notBeforeField
->Data
;
220 if(timeStringToTm((char *)xNotBefore
->time
.Data
, xNotBefore
->time
.Length
,
222 errorLog0("TPCertInfo::isCurrent: malformed notBefore time\n");
223 crtn
= CSSMERR_TP_INVALID_CERT_POINTER
;
226 if(compareTimes(&now
, ¬Before
) < 0) {
227 crtn
= CSSMERR_TP_CERT_NOT_VALID_YET
;
228 tpTimeDbg("\nTP_CERT_NOT_VALID_YET:\n now y:%d m:%d d:%d h:%d m:%d",
229 now
.tm_year
, now
.tm_mon
, now
.tm_mday
, now
.tm_hour
,
231 tpTimeDbg(" notBefore y:%d m:%d d:%d h:%d m:%d",
232 notBefore
.tm_year
, notBefore
.tm_mon
, notBefore
.tm_mday
,
233 notBefore
.tm_hour
, notBefore
.tm_min
);
236 StLock
<Mutex
> _(tpTimeLock());
239 tpTimeDbg(" now2 y:%d m:%d d:%d h:%d m:%d",
240 now2
.tm_year
, now2
.tm_mon
, now2
.tm_mday
, now2
.tm_hour
,
247 crtn
= fetchField(&CSSMOID_X509V1ValidityNotAfter
, ¬AfterField
);
249 errorLog0("TPCertInfo::isCurrent: GetField error");
253 CSSM_X509_TIME
*xNotAfter
= (CSSM_X509_TIME
*)notAfterField
->Data
;
254 if(timeStringToTm((char *)xNotAfter
->time
.Data
, xNotAfter
->time
.Length
,
256 errorLog0("TPCertInfo::isCurrent: malformed notAfter time\n");
257 crtn
= CSSMERR_TP_INVALID_CERT_POINTER
;
259 else if(compareTimes(&now
, ¬After
) > 0) {
260 crtn
= CSSMERR_TP_CERT_EXPIRED
;
261 tpTimeDbg("\nTP_CERT_EXPIRED: \n now y:%d m:%d d:%d "
263 now
.tm_year
, now
.tm_mon
, now
.tm_mday
,
264 now
.tm_hour
, now
.tm_min
);
265 tpTimeDbg(" notAfter y:%d m:%d d:%d h:%d m:%d",
266 notAfter
.tm_year
, notAfter
.tm_mon
, notAfter
.tm_mday
,
267 notAfter
.tm_hour
, notAfter
.tm_min
);
270 StLock
<Mutex
> _(tpTimeLock());
273 tpTimeDbg(" now2 y:%d m:%d d:%d h:%d m:%d",
274 now2
.tm_year
, now2
.tm_mon
, now2
.tm_mday
, now2
.tm_hour
,
286 freeField(&CSSMOID_X509V1ValidityNotAfter
, notAfterField
);
289 freeField(&CSSMOID_X509V1ValidityNotBefore
, notBeforeField
);
295 *** TPCertGroup class
297 TPCertGroup::TPCertGroup(
298 CssmAllocator
&alloc
,
303 mCertInfo
= (TPCertInfo
**)alloc
.malloc(numCerts
* sizeof(TPCertInfo
*));
304 mSizeofCertInfo
= numCerts
;
308 * Deletes all TPCertInfo's.
310 TPCertGroup::~TPCertGroup()
313 for(i
=0; i
<mNumCerts
; i
++) {
316 mAlloc
.free(mCertInfo
);
319 /* add/remove/access TPTCertInfo's. */
320 void TPCertGroup::appendCert(
321 TPCertInfo
*certInfo
) // appends to end of mCertInfo
323 if(mNumCerts
== mSizeofCertInfo
) {
324 /* FIXME - do we need the realloc workaround we used to have in TPSession? */
325 mSizeofCertInfo
*= 2;
326 mCertInfo
= (TPCertInfo
**)mAlloc
.realloc(mCertInfo
,
327 mSizeofCertInfo
* sizeof(TPCertInfo
*));
329 mCertInfo
[mNumCerts
++] = certInfo
;
332 TPCertInfo
*TPCertGroup::certAtIndex(
335 if(index
> (mNumCerts
- 1)) {
336 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR
);
338 return mCertInfo
[index
];
341 TPCertInfo
*TPCertGroup::removeCertAtIndex(
342 unsigned index
) // doesn't delete the cert, just
343 // removes it from out list
345 if(index
> (mNumCerts
- 1)) {
346 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR
);
348 TPCertInfo
*rtn
= mCertInfo
[index
];
350 /* removed requested element and compact remaining array */
352 for(i
=index
; i
<(mNumCerts
- 1); i
++) {
353 mCertInfo
[i
] = mCertInfo
[i
+1];
359 unsigned TPCertGroup::numCerts()
364 TPCertInfo
*TPCertGroup::firstCert()
367 /* the caller really should not do this... */
368 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR
);
375 TPCertInfo
*TPCertGroup::lastCert()
378 /* the caller really should not do this... */
379 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR
);
382 return mCertInfo
[mNumCerts
- 1];
386 /* build a CSSM_CERTGROUP corresponding with our mCertInfo */
387 CSSM_CERTGROUP_PTR
TPCertGroup::buildCssmCertGroup()
389 CSSM_CERTGROUP_PTR cgrp
=
390 (CSSM_CERTGROUP_PTR
)mAlloc
.malloc(sizeof(CSSM_CERTGROUP
));
391 cgrp
->NumCerts
= mNumCerts
;
392 cgrp
->CertGroupType
= CSSM_CERTGROUP_ENCODED_CERT
;
393 cgrp
->CertType
= CSSM_CERT_X_509v3
;
394 cgrp
->CertEncoding
= CSSM_CERT_ENCODING_DER
;
397 cgrp
->GroupList
.CertList
= NULL
;
400 cgrp
->GroupList
.CertList
= (CSSM_DATA_PTR
)mAlloc
.calloc(mNumCerts
,
402 for(unsigned i
=0; i
<mNumCerts
; i
++) {
403 tpCopyCssmData(mAlloc
, mCertInfo
[i
]->certData(),
404 &cgrp
->GroupList
.CertList
[i
]);