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