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>
34 // ??? #include "clExtensionTemplates.h"
36 DecodedCert::DecodedCert(
37 AppleX509CLSession
&session
)
38 : DecodedItem(session
)
40 memset(&mCert
, 0, sizeof(mCert
));
43 /* one-shot constructor, decoding from DER-encoded data */
44 DecodedCert::DecodedCert(
45 AppleX509CLSession
&session
,
46 const CssmData
&encodedCert
)
47 : DecodedItem(session
)
49 memset(&mCert
, 0, sizeof(mCert
));
50 PRErrorCode prtn
= mCoder
.decode(encodedCert
.data(), encodedCert
.length(),
51 NSS_SignedCertTemplate
, &mCert
);
53 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
55 mDecodedExtensions
.decodeFromNss(mCert
.tbs
.extensions
);
56 mState
= IS_DecodedAll
;
59 DecodedCert::~DecodedCert()
63 /* decode TBSCert and its extensions */
64 void DecodedCert::decodeTbs(
65 const CssmData
&encodedTbs
)
67 assert(mState
== IS_Empty
);
69 memset(&mCert
, 0, sizeof(mCert
));
70 PRErrorCode prtn
= mCoder
.decode(encodedTbs
.data(), encodedTbs
.length(),
71 NSS_TBSCertificateTemplate
, &mCert
.tbs
);
73 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
75 mDecodedExtensions
.decodeFromNss(mCert
.tbs
.extensions
);
76 mState
= IS_DecodedTBS
;
79 void DecodedCert::encodeExtensions()
81 NSS_TBSCertificate
&tbs
= mCert
.tbs
;
82 assert(mState
== IS_Building
);
83 assert(tbs
.extensions
== NULL
);
85 if(mDecodedExtensions
.numExtensions() == 0) {
86 /* no extensions, no error */
89 mDecodedExtensions
.encodeToNss(tbs
.extensions
);
93 * FIXME : how to determine max encoding size at run time!?
95 #define MAX_TEMPLATE_SIZE (8 * 1024)
97 /* encode TBS component; only called from CertCreateTemplate */
98 void DecodedCert::encodeTbs(
99 CssmOwnedData
&encodedTbs
)
102 assert(mState
== IS_Building
);
104 /* enforce required fields - could go deeper, maybe we should */
105 NSS_TBSCertificate
&tbs
= mCert
.tbs
;
106 if((tbs
.signature
.algorithm
.Data
== NULL
) ||
107 (tbs
.issuer
.rdns
== NULL
) ||
108 (tbs
.subject
.rdns
== NULL
) ||
109 (tbs
.subjectPublicKeyInfo
.subjectPublicKey
.Data
== NULL
)) {
110 clErrorLog("DecodedCert::encodeTbs: incomplete TBS");
111 /* an odd, undocumented error return */
112 CssmError::throwMe(CSSMERR_CL_NO_FIELD_VALUES
);
116 prtn
= SecNssEncodeItemOdata(&tbs
, NSS_TBSCertificateTemplate
,
119 CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR
);
124 * Cook up CSSM_KEYUSE, gleaning as much as possible from
125 * (optional) extensions. If no applicable extensions available,
126 * we'll just return CSSM_KEYUSE_ANY.
128 * Note that the standard KeyUsage flags involving 'signing' translate
129 * to verify since we're only dealing with public keys.
131 CSSM_KEYUSE
DecodedCert::inferKeyUsage() const
133 CSSM_KEYUSE keyUse
= 0;
134 const DecodedExten
*decodedExten
;
138 decodedExten
= DecodedItem::findDecodedExt(CSSMOID_KeyUsage
, false,
141 CSSM_DATA
*ku
= (CSSM_DATA
*)decodedExten
->nssObj();
143 CE_KeyUsage kuse
= clBitStringToKeyUsage(*ku
);
144 if(kuse
& CE_KU_DigitalSignature
) {
145 keyUse
|= CSSM_KEYUSE_VERIFY
;
147 if(kuse
& CE_KU_NonRepudiation
) {
148 keyUse
|= CSSM_KEYUSE_VERIFY
;
150 if(kuse
& CE_KU_KeyEncipherment
) {
151 keyUse
|= CSSM_KEYUSE_WRAP
;
153 if(kuse
& CE_KU_KeyAgreement
) {
154 keyUse
|= CSSM_KEYUSE_DERIVE
;
156 if(kuse
& CE_KU_KeyCertSign
) {
157 keyUse
|= CSSM_KEYUSE_VERIFY
;
159 if(kuse
& CE_KU_CRLSign
) {
160 keyUse
|= CSSM_KEYUSE_VERIFY
;
162 if(kuse
& CE_KU_DataEncipherment
) {
163 keyUse
|= CSSM_KEYUSE_ENCRYPT
;
167 /* Extended key usage */
168 decodedExten
= DecodedItem::findDecodedExt(CSSMOID_ExtendedKeyUsage
,
169 false, 0, numFields
);
171 NSS_ExtKeyUsage
*euse
= (NSS_ExtKeyUsage
*)decodedExten
->nssObj();
172 assert(euse
!= NULL
);
173 unsigned numUses
= clNssArraySize((const void **)euse
->purposes
);
174 for(unsigned dex
=0; dex
<numUses
; dex
++) {
175 const CSSM_OID
*thisUse
= euse
->purposes
[dex
];
176 if(clCompareCssmData(thisUse
, &CSSMOID_ExtendedKeyUsageAny
)) {
178 keyUse
= CSSM_KEYUSE_ANY
;
181 else if(clCompareCssmData(thisUse
, &CSSMOID_ServerAuth
)) {
182 keyUse
|= (CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_ENCRYPT
);
184 else if(clCompareCssmData(thisUse
, &CSSMOID_ClientAuth
)) {
185 keyUse
|= (CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_ENCRYPT
);
187 else if(clCompareCssmData(thisUse
, &CSSMOID_ExtendedUseCodeSigning
)) {
188 keyUse
|= CSSM_KEYUSE_VERIFY
;
190 else if(clCompareCssmData(thisUse
, &CSSMOID_EmailProtection
)) {
192 (CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_DERIVE
);
194 else if(clCompareCssmData(thisUse
, &CSSMOID_TimeStamping
)) {
195 keyUse
|= CSSM_KEYUSE_VERIFY
;
197 else if(clCompareCssmData(thisUse
, &CSSMOID_OCSPSigning
)) {
198 keyUse
|= CSSM_KEYUSE_VERIFY
;
203 /* Nothing found; take the default. */
204 keyUse
= CSSM_KEYUSE_ANY
;
210 * Obtain a CSSM_KEY from a decoded cert, inferring as much as we can
211 * from required fields (subjectPublicKeyInfo) and extensions (for
214 CSSM_KEY_PTR
DecodedCert::extractCSSMKey(
215 CssmAllocator
&alloc
) const
217 const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
&keyInfo
=
218 mCert
.tbs
.subjectPublicKeyInfo
;
219 return CL_extractCSSMKeyNSS(keyInfo
, alloc
, this);