]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_x509_cl/lib/DecodedCert.cpp
Security-58286.1.32.tar.gz
[apple/security.git] / OSX / libsecurity_apple_x509_cl / lib / DecodedCert.cpp
1 /*
2 * Copyright (c) 2000-2001,2011,2014 Apple Inc. All Rights Reserved.
3 *
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
8 * using this file.
9 *
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.
16 */
17
18
19 /*
20 * DecodedCert.cpp - object representing a decoded cert, in NSS
21 * format, with extensions parsed and decoded (still in NSS format).
22 *
23 * Copyright (c) 2000,2011,2014 Apple Inc.
24 */
25
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>
33
34 DecodedCert::DecodedCert(
35 AppleX509CLSession &session)
36 : DecodedItem(session)
37 {
38 memset(&mCert, 0, sizeof(mCert));
39 }
40
41 /* one-shot constructor, decoding from DER-encoded data */
42 DecodedCert::DecodedCert(
43 AppleX509CLSession &session,
44 const CssmData &encodedCert)
45 : DecodedItem(session)
46 {
47 memset(&mCert, 0, sizeof(mCert));
48 PRErrorCode prtn = mCoder.decode(encodedCert.data(), encodedCert.length(),
49 kSecAsn1SignedCertTemplate, &mCert);
50 if(prtn) {
51 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
52 }
53 mDecodedExtensions.decodeFromNss(mCert.tbs.extensions);
54 mState = IS_DecodedAll;
55 }
56
57 DecodedCert::~DecodedCert()
58 {
59 }
60
61 /* decode TBSCert and its extensions */
62 void DecodedCert::decodeTbs(
63 const CssmData &encodedTbs)
64 {
65 assert(mState == IS_Empty);
66
67 memset(&mCert, 0, sizeof(mCert));
68 PRErrorCode prtn = mCoder.decode(encodedTbs.data(), encodedTbs.length(),
69 kSecAsn1TBSCertificateTemplate, &mCert.tbs);
70 if(prtn) {
71 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
72 }
73 mDecodedExtensions.decodeFromNss(mCert.tbs.extensions);
74 mState = IS_DecodedTBS;
75 }
76
77 void DecodedCert::encodeExtensions()
78 {
79 NSS_TBSCertificate &tbs = mCert.tbs;
80 assert(mState == IS_Building);
81 assert(tbs.extensions == NULL);
82
83 if(mDecodedExtensions.numExtensions() == 0) {
84 /* no extensions, no error */
85 return;
86 }
87 mDecodedExtensions.encodeToNss(tbs.extensions);
88 }
89
90 /*
91 * FIXME : how to determine max encoding size at run time!?
92 */
93 #define MAX_TEMPLATE_SIZE (8 * 1024)
94
95 /* encode TBS component; only called from CertCreateTemplate */
96 void DecodedCert::encodeTbs(
97 CssmOwnedData &encodedTbs)
98 {
99 encodeExtensions();
100 assert(mState == IS_Building);
101
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);
111 }
112
113 PRErrorCode prtn;
114 prtn = SecNssEncodeItemOdata(&tbs, kSecAsn1TBSCertificateTemplate,
115 encodedTbs);
116 if(prtn) {
117 CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
118 }
119 }
120
121 /*
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.
125 *
126 * Note that the standard KeyUsage flags involving 'signing' translate
127 * to verify since we're only dealing with public keys.
128 */
129 CSSM_KEYUSE DecodedCert::inferKeyUsage() const
130 {
131 CSSM_KEYUSE keyUse = 0;
132 const DecodedExten *decodedExten;
133 uint32 numFields;
134
135 /* Basic KeyUsage */
136 decodedExten = DecodedItem::findDecodedExt(CSSMOID_KeyUsage, false,
137 0, numFields);
138 if(decodedExten) {
139 CSSM_DATA *ku = (CSSM_DATA *)decodedExten->nssObj();
140 assert(ku != NULL);
141 CE_KeyUsage kuse = clBitStringToKeyUsage(*ku);
142 if(kuse & CE_KU_DigitalSignature) {
143 keyUse |= CSSM_KEYUSE_VERIFY;
144 }
145 if(kuse & CE_KU_NonRepudiation) {
146 keyUse |= CSSM_KEYUSE_VERIFY;
147 }
148 if(kuse & CE_KU_KeyEncipherment) {
149 keyUse |= CSSM_KEYUSE_WRAP;
150 }
151 if(kuse & CE_KU_KeyAgreement) {
152 keyUse |= CSSM_KEYUSE_DERIVE;
153 }
154 if(kuse & CE_KU_KeyCertSign) {
155 keyUse |= CSSM_KEYUSE_VERIFY;
156 }
157 if(kuse & CE_KU_CRLSign) {
158 keyUse |= CSSM_KEYUSE_VERIFY;
159 }
160 if(kuse & CE_KU_DataEncipherment) {
161 keyUse |= CSSM_KEYUSE_ENCRYPT;
162 }
163 }
164
165 /* Extended key usage */
166 decodedExten = DecodedItem::findDecodedExt(CSSMOID_ExtendedKeyUsage,
167 false, 0, numFields);
168 if(decodedExten) {
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)) {
175 /* we're done */
176 keyUse = CSSM_KEYUSE_ANY;
177 break;
178 }
179 else if(clCompareCssmData(thisUse, &CSSMOID_ServerAuth)) {
180 keyUse |= (CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DERIVE);
181 }
182 else if(clCompareCssmData(thisUse, &CSSMOID_ClientAuth)) {
183 keyUse |= (CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DERIVE);
184 }
185 else if(clCompareCssmData(thisUse, &CSSMOID_ExtendedUseCodeSigning)) {
186 keyUse |= CSSM_KEYUSE_VERIFY;
187 }
188 else if(clCompareCssmData(thisUse, &CSSMOID_EmailProtection)) {
189 keyUse |=
190 (CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_DERIVE);
191 }
192 else if(clCompareCssmData(thisUse, &CSSMOID_TimeStamping)) {
193 keyUse |= CSSM_KEYUSE_VERIFY;
194 }
195 else if(clCompareCssmData(thisUse, &CSSMOID_OCSPSigning)) {
196 keyUse |= CSSM_KEYUSE_VERIFY;
197 }
198 else if(clCompareCssmData(thisUse, &CSSMOID_APPLE_EKU_SYSTEM_IDENTITY)) {
199 /* system identity - fairly liberal: CMS as well as SSL */
200 keyUse |=
201 (CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_ENCRYPT);
202 }
203 else if(clCompareCssmData(thisUse, &CSSMOID_KERBv5_PKINIT_KP_CLIENT_AUTH)) {
204 /*
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
208 */
209 keyUse |= (CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP);
210 }
211 else if(clCompareCssmData(thisUse, &CSSMOID_KERBv5_PKINIT_KP_KDC)) {
212 /*
213 * Kerberos PKINIT server:
214 * -- client verifies KDC signature in a CMS msg in AS-REP
215 */
216 keyUse |= CSSM_KEYUSE_VERIFY;
217 }
218 }
219 }
220
221 /* NetscapeCertType */
222 decodedExten = DecodedItem::findDecodedExt(CSSMOID_NetscapeCertType,
223 false, 0, numFields);
224 if(decodedExten) {
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];
231 }
232
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;
237 }
238 }
239 }
240 if(keyUse == 0) {
241 /* Nothing found; take the default. */
242 keyUse = CSSM_KEYUSE_ANY;
243 }
244 return keyUse;
245 }
246
247 /*
248 * Obtain a CSSM_KEY from a decoded cert, inferring as much as we can
249 * from required fields (subjectPublicKeyInfo) and extensions (for
250 * KeyUse).
251 */
252 CSSM_KEY_PTR DecodedCert::extractCSSMKey(
253 Allocator &alloc) const
254 {
255 const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &keyInfo =
256 mCert.tbs.subjectPublicKeyInfo;
257 return CL_extractCSSMKeyNSS(keyInfo, alloc, this);
258 }
259