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 * DecodedCert.cpp - object representing a decoded cert, in NSS
21 * format, with extensions parsed and decoded (still in NSS format).
23 * Created 9/1/2000 by Doug Mitchell.
24 * Copyright (c) 2000 by Apple Computer.
27 #include "DecodedCert.h"
28 #include "clNssUtils.h"
29 #include "cldebugging.h"
30 #include "AppleX509CLSession.h"
31 #include "CSPAttacher.h"
32 #include <Security/cssmapple.h>
33 #include <Security/oidscert.h>
35 DecodedCert::DecodedCert(
36 AppleX509CLSession
&session
)
37 : DecodedItem(session
)
39 memset(&mCert
, 0, sizeof(mCert
));
42 /* one-shot constructor, decoding from DER-encoded data */
43 DecodedCert::DecodedCert(
44 AppleX509CLSession
&session
,
45 const CssmData
&encodedCert
)
46 : DecodedItem(session
)
48 memset(&mCert
, 0, sizeof(mCert
));
49 PRErrorCode prtn
= mCoder
.decode(encodedCert
.data(), encodedCert
.length(),
50 kSecAsn1SignedCertTemplate
, &mCert
);
52 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
54 mDecodedExtensions
.decodeFromNss(mCert
.tbs
.extensions
);
55 mState
= IS_DecodedAll
;
58 DecodedCert::~DecodedCert()
62 /* decode TBSCert and its extensions */
63 void DecodedCert::decodeTbs(
64 const CssmData
&encodedTbs
)
66 assert(mState
== IS_Empty
);
68 memset(&mCert
, 0, sizeof(mCert
));
69 PRErrorCode prtn
= mCoder
.decode(encodedTbs
.data(), encodedTbs
.length(),
70 kSecAsn1TBSCertificateTemplate
, &mCert
.tbs
);
72 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
74 mDecodedExtensions
.decodeFromNss(mCert
.tbs
.extensions
);
75 mState
= IS_DecodedTBS
;
78 void DecodedCert::encodeExtensions()
80 NSS_TBSCertificate
&tbs
= mCert
.tbs
;
81 assert(mState
== IS_Building
);
82 assert(tbs
.extensions
== NULL
);
84 if(mDecodedExtensions
.numExtensions() == 0) {
85 /* no extensions, no error */
88 mDecodedExtensions
.encodeToNss(tbs
.extensions
);
92 * FIXME : how to determine max encoding size at run time!?
94 #define MAX_TEMPLATE_SIZE (8 * 1024)
96 /* encode TBS component; only called from CertCreateTemplate */
97 void DecodedCert::encodeTbs(
98 CssmOwnedData
&encodedTbs
)
101 assert(mState
== IS_Building
);
103 /* enforce required fields - could go deeper, maybe we should */
104 NSS_TBSCertificate
&tbs
= mCert
.tbs
;
105 if((tbs
.signature
.algorithm
.Data
== NULL
) ||
106 (tbs
.issuer
.rdns
== NULL
) ||
107 (tbs
.subject
.rdns
== NULL
) ||
108 (tbs
.subjectPublicKeyInfo
.subjectPublicKey
.Data
== NULL
)) {
109 clErrorLog("DecodedCert::encodeTbs: incomplete TBS");
110 /* an odd, undocumented error return */
111 CssmError::throwMe(CSSMERR_CL_NO_FIELD_VALUES
);
115 prtn
= SecNssEncodeItemOdata(&tbs
, kSecAsn1TBSCertificateTemplate
,
118 CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR
);
123 * Cook up CSSM_KEYUSE, gleaning as much as possible from
124 * (optional) extensions. If no applicable extensions available,
125 * we'll just return CSSM_KEYUSE_ANY.
127 * Note that the standard KeyUsage flags involving 'signing' translate
128 * to verify since we're only dealing with public keys.
130 CSSM_KEYUSE
DecodedCert::inferKeyUsage() const
132 CSSM_KEYUSE keyUse
= 0;
133 const DecodedExten
*decodedExten
;
137 decodedExten
= DecodedItem::findDecodedExt(CSSMOID_KeyUsage
, false,
140 CSSM_DATA
*ku
= (CSSM_DATA
*)decodedExten
->nssObj();
142 CE_KeyUsage kuse
= clBitStringToKeyUsage(*ku
);
143 if(kuse
& CE_KU_DigitalSignature
) {
144 keyUse
|= CSSM_KEYUSE_VERIFY
;
146 if(kuse
& CE_KU_NonRepudiation
) {
147 keyUse
|= CSSM_KEYUSE_VERIFY
;
149 if(kuse
& CE_KU_KeyEncipherment
) {
150 keyUse
|= CSSM_KEYUSE_WRAP
;
152 if(kuse
& CE_KU_KeyAgreement
) {
153 keyUse
|= CSSM_KEYUSE_DERIVE
;
155 if(kuse
& CE_KU_KeyCertSign
) {
156 keyUse
|= CSSM_KEYUSE_VERIFY
;
158 if(kuse
& CE_KU_CRLSign
) {
159 keyUse
|= CSSM_KEYUSE_VERIFY
;
161 if(kuse
& CE_KU_DataEncipherment
) {
162 keyUse
|= CSSM_KEYUSE_ENCRYPT
;
166 /* Extended key usage */
167 decodedExten
= DecodedItem::findDecodedExt(CSSMOID_ExtendedKeyUsage
,
168 false, 0, numFields
);
170 NSS_ExtKeyUsage
*euse
= (NSS_ExtKeyUsage
*)decodedExten
->nssObj();
171 assert(euse
!= NULL
);
172 unsigned numUses
= clNssArraySize((const void **)euse
->purposes
);
173 for(unsigned dex
=0; dex
<numUses
; dex
++) {
174 const CSSM_OID
*thisUse
= euse
->purposes
[dex
];
175 if(clCompareCssmData(thisUse
, &CSSMOID_ExtendedKeyUsageAny
)) {
177 keyUse
= CSSM_KEYUSE_ANY
;
180 else if(clCompareCssmData(thisUse
, &CSSMOID_ServerAuth
)) {
181 keyUse
|= (CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DERIVE
);
183 else if(clCompareCssmData(thisUse
, &CSSMOID_ClientAuth
)) {
184 keyUse
|= (CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DERIVE
);
186 else if(clCompareCssmData(thisUse
, &CSSMOID_ExtendedUseCodeSigning
)) {
187 keyUse
|= CSSM_KEYUSE_VERIFY
;
189 else if(clCompareCssmData(thisUse
, &CSSMOID_EmailProtection
)) {
191 (CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_DERIVE
);
193 else if(clCompareCssmData(thisUse
, &CSSMOID_TimeStamping
)) {
194 keyUse
|= CSSM_KEYUSE_VERIFY
;
196 else if(clCompareCssmData(thisUse
, &CSSMOID_OCSPSigning
)) {
197 keyUse
|= CSSM_KEYUSE_VERIFY
;
199 else if(clCompareCssmData(thisUse
, &CSSMOID_APPLE_EKU_SYSTEM_IDENTITY
)) {
200 /* system identity - fairly liberal: CMS as well as SSL */
202 (CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_ENCRYPT
);
204 else if(clCompareCssmData(thisUse
, &CSSMOID_KERBv5_PKINIT_KP_CLIENT_AUTH
)) {
206 * Kerberos PKINIT client:
207 * -- KDC verifies client signature in a CMS msg in AS-REQ
208 * -- KDC encrypts for client in a CMS msg in AS-REP
210 keyUse
|= (CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_WRAP
);
212 else if(clCompareCssmData(thisUse
, &CSSMOID_KERBv5_PKINIT_KP_KDC
)) {
214 * Kerberos PKINIT server:
215 * -- client verifies KDC signature in a CMS msg in AS-REP
217 keyUse
|= CSSM_KEYUSE_VERIFY
;
222 /* NetscapeCertType */
223 decodedExten
= DecodedItem::findDecodedExt(CSSMOID_NetscapeCertType
,
224 false, 0, numFields
);
226 /* nssObj() is a CSSM_DATA ptr, whose Data points to the bits we want */
227 CSSM_DATA
*nctData
= (CSSM_DATA
*)decodedExten
->nssObj();
228 if((nctData
!= NULL
) && (nctData
->Length
> 0)) {
229 CE_NetscapeCertType nct
= ((uint16
)nctData
->Data
[0]) << 8;
230 if(nctData
->Length
> 1) {
231 nct
|= nctData
->Data
[1];
234 /* All this usage bits imply signature verify capability */
235 if(nct
& (CE_NCT_SSL_Client
| CE_NCT_SSL_Server
| CE_NCT_SMIME
| CE_NCT_ObjSign
|
236 CE_NCT_SSL_CA
| CE_NCT_SMIME_CA
| CE_NCT_ObjSignCA
)) {
237 keyUse
|= CSSM_KEYUSE_VERIFY
;
242 /* Nothing found; take the default. */
243 keyUse
= CSSM_KEYUSE_ANY
;
249 * Obtain a CSSM_KEY from a decoded cert, inferring as much as we can
250 * from required fields (subjectPublicKeyInfo) and extensions (for
253 CSSM_KEY_PTR
DecodedCert::extractCSSMKey(
254 Allocator
&alloc
) const
256 const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
&keyInfo
=
257 mCert
.tbs
.subjectPublicKeyInfo
;
258 return CL_extractCSSMKeyNSS(keyInfo
, alloc
, this);