2 * Copyright (c) 2000-2001,2011,2014 Apple 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 * Copyright (c) 2000,2011,2014 Apple Inc.
26 #include "DecodedCert.h"
27 #include "clNssUtils.h"
28 #include "cldebugging.h"
29 #include "AppleX509CLSession.h"
30 #include "CSPAttacher.h"
31 #include <Security/cssmapple.h>
32 #include <Security/oidscert.h>
34 DecodedCert::DecodedCert(
35 AppleX509CLSession
&session
)
36 : DecodedItem(session
)
38 memset(&mCert
, 0, sizeof(mCert
));
41 /* one-shot constructor, decoding from DER-encoded data */
42 DecodedCert::DecodedCert(
43 AppleX509CLSession
&session
,
44 const CssmData
&encodedCert
)
45 : DecodedItem(session
)
47 memset(&mCert
, 0, sizeof(mCert
));
48 PRErrorCode prtn
= mCoder
.decode(encodedCert
.data(), encodedCert
.length(),
49 kSecAsn1SignedCertTemplate
, &mCert
);
51 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
53 mDecodedExtensions
.decodeFromNss(mCert
.tbs
.extensions
);
54 mState
= IS_DecodedAll
;
57 DecodedCert::~DecodedCert()
61 /* decode TBSCert and its extensions */
62 void DecodedCert::decodeTbs(
63 const CssmData
&encodedTbs
)
65 assert(mState
== IS_Empty
);
67 memset(&mCert
, 0, sizeof(mCert
));
68 PRErrorCode prtn
= mCoder
.decode(encodedTbs
.data(), encodedTbs
.length(),
69 kSecAsn1TBSCertificateTemplate
, &mCert
.tbs
);
71 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
73 mDecodedExtensions
.decodeFromNss(mCert
.tbs
.extensions
);
74 mState
= IS_DecodedTBS
;
77 void DecodedCert::encodeExtensions()
79 NSS_TBSCertificate
&tbs
= mCert
.tbs
;
80 assert(mState
== IS_Building
);
81 assert(tbs
.extensions
== NULL
);
83 if(mDecodedExtensions
.numExtensions() == 0) {
84 /* no extensions, no error */
87 mDecodedExtensions
.encodeToNss(tbs
.extensions
);
91 * FIXME : how to determine max encoding size at run time!?
93 #define MAX_TEMPLATE_SIZE (8 * 1024)
95 /* encode TBS component; only called from CertCreateTemplate */
96 void DecodedCert::encodeTbs(
97 CssmOwnedData
&encodedTbs
)
100 assert(mState
== IS_Building
);
102 /* enforce required fields - could go deeper, maybe we should */
103 NSS_TBSCertificate
&tbs
= mCert
.tbs
;
104 if((tbs
.signature
.algorithm
.Data
== NULL
) ||
105 (tbs
.issuer
.rdns
== NULL
) ||
106 (tbs
.subject
.rdns
== NULL
) ||
107 (tbs
.subjectPublicKeyInfo
.subjectPublicKey
.Data
== NULL
)) {
108 clErrorLog("DecodedCert::encodeTbs: incomplete TBS");
109 /* an odd, undocumented error return */
110 CssmError::throwMe(CSSMERR_CL_NO_FIELD_VALUES
);
114 prtn
= SecNssEncodeItemOdata(&tbs
, kSecAsn1TBSCertificateTemplate
,
117 CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR
);
122 * Cook up CSSM_KEYUSE, gleaning as much as possible from
123 * (optional) extensions. If no applicable extensions available,
124 * we'll just return CSSM_KEYUSE_ANY.
126 * Note that the standard KeyUsage flags involving 'signing' translate
127 * to verify since we're only dealing with public keys.
129 CSSM_KEYUSE
DecodedCert::inferKeyUsage() const
131 CSSM_KEYUSE keyUse
= 0;
132 const DecodedExten
*decodedExten
;
136 decodedExten
= DecodedItem::findDecodedExt(CSSMOID_KeyUsage
, false,
139 CSSM_DATA
*ku
= (CSSM_DATA
*)decodedExten
->nssObj();
141 CE_KeyUsage kuse
= clBitStringToKeyUsage(*ku
);
142 if(kuse
& CE_KU_DigitalSignature
) {
143 keyUse
|= CSSM_KEYUSE_VERIFY
;
145 if(kuse
& CE_KU_NonRepudiation
) {
146 keyUse
|= CSSM_KEYUSE_VERIFY
;
148 if(kuse
& CE_KU_KeyEncipherment
) {
149 keyUse
|= CSSM_KEYUSE_WRAP
;
151 if(kuse
& CE_KU_KeyAgreement
) {
152 keyUse
|= CSSM_KEYUSE_DERIVE
;
154 if(kuse
& CE_KU_KeyCertSign
) {
155 keyUse
|= CSSM_KEYUSE_VERIFY
;
157 if(kuse
& CE_KU_CRLSign
) {
158 keyUse
|= CSSM_KEYUSE_VERIFY
;
160 if(kuse
& CE_KU_DataEncipherment
) {
161 keyUse
|= CSSM_KEYUSE_ENCRYPT
;
165 /* Extended key usage */
166 decodedExten
= DecodedItem::findDecodedExt(CSSMOID_ExtendedKeyUsage
,
167 false, 0, numFields
);
169 NSS_ExtKeyUsage
*euse
= (NSS_ExtKeyUsage
*)decodedExten
->nssObj();
170 assert(euse
!= NULL
);
171 unsigned numUses
= clNssArraySize((const void **)euse
->purposes
);
172 for(unsigned dex
=0; dex
<numUses
; dex
++) {
173 const CSSM_OID
*thisUse
= euse
->purposes
[dex
];
174 if(clCompareCssmData(thisUse
, &CSSMOID_ExtendedKeyUsageAny
)) {
176 keyUse
= CSSM_KEYUSE_ANY
;
179 else if(clCompareCssmData(thisUse
, &CSSMOID_ServerAuth
)) {
180 keyUse
|= (CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DERIVE
);
182 else if(clCompareCssmData(thisUse
, &CSSMOID_ClientAuth
)) {
183 keyUse
|= (CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DERIVE
);
185 else if(clCompareCssmData(thisUse
, &CSSMOID_ExtendedUseCodeSigning
)) {
186 keyUse
|= CSSM_KEYUSE_VERIFY
;
188 else if(clCompareCssmData(thisUse
, &CSSMOID_EmailProtection
)) {
190 (CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_DERIVE
);
192 else if(clCompareCssmData(thisUse
, &CSSMOID_TimeStamping
)) {
193 keyUse
|= CSSM_KEYUSE_VERIFY
;
195 else if(clCompareCssmData(thisUse
, &CSSMOID_OCSPSigning
)) {
196 keyUse
|= CSSM_KEYUSE_VERIFY
;
198 else if(clCompareCssmData(thisUse
, &CSSMOID_APPLE_EKU_SYSTEM_IDENTITY
)) {
199 /* system identity - fairly liberal: CMS as well as SSL */
201 (CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_ENCRYPT
);
203 else if(clCompareCssmData(thisUse
, &CSSMOID_KERBv5_PKINIT_KP_CLIENT_AUTH
)) {
205 * Kerberos PKINIT client:
206 * -- KDC verifies client signature in a CMS msg in AS-REQ
207 * -- KDC encrypts for client in a CMS msg in AS-REP
209 keyUse
|= (CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_WRAP
);
211 else if(clCompareCssmData(thisUse
, &CSSMOID_KERBv5_PKINIT_KP_KDC
)) {
213 * Kerberos PKINIT server:
214 * -- client verifies KDC signature in a CMS msg in AS-REP
216 keyUse
|= CSSM_KEYUSE_VERIFY
;
221 /* NetscapeCertType */
222 decodedExten
= DecodedItem::findDecodedExt(CSSMOID_NetscapeCertType
,
223 false, 0, numFields
);
225 /* nssObj() is a CSSM_DATA ptr, whose Data points to the bits we want */
226 CSSM_DATA
*nctData
= (CSSM_DATA
*)decodedExten
->nssObj();
227 if((nctData
!= NULL
) && (nctData
->Length
> 0)) {
228 CE_NetscapeCertType nct
= ((uint16
)nctData
->Data
[0]) << 8;
229 if(nctData
->Length
> 1) {
230 nct
|= nctData
->Data
[1];
233 /* All this usage bits imply signature verify capability */
234 if(nct
& (CE_NCT_SSL_Client
| CE_NCT_SSL_Server
| CE_NCT_SMIME
| CE_NCT_ObjSign
|
235 CE_NCT_SSL_CA
| CE_NCT_SMIME_CA
| CE_NCT_ObjSignCA
)) {
236 keyUse
|= CSSM_KEYUSE_VERIFY
;
241 /* Nothing found; take the default. */
242 keyUse
= CSSM_KEYUSE_ANY
;
248 * Obtain a CSSM_KEY from a decoded cert, inferring as much as we can
249 * from required fields (subjectPublicKeyInfo) and extensions (for
252 CSSM_KEY_PTR
DecodedCert::extractCSSMKey(
253 Allocator
&alloc
) const
255 const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
&keyInfo
=
256 mCert
.tbs
.subjectPublicKeyInfo
;
257 return CL_extractCSSMKeyNSS(keyInfo
, alloc
, this);