1/* 2 * crlUtils.cpp - CRL CL/TP/DL utilities. 3 */ 4#include <Security/cssmtype.h> 5#include <Security/cssmapi.h> 6#include <utilLib/common.h> 7#include <clAppUtils/timeStr.h> 8#include <clAppUtils/crlUtils.h> 9#include <Security/oidsattr.h> 10#include <Security/oidscert.h> 11#include <Security/oidscrl.h> 12#include <stdlib.h> 13#include <stdio.h> 14#include <string.h> 15#include <security_cdsa_utilities/Schema.h> /* private API */ 16 17/* crlAddCrlToDb() removed due to build problem; obsoleted in favor of 18 * cuAddCrlToDb() in security_cdsa_utils 19 */ 20#define CRL_ADD_TO_DB 0 21 22#if CRL_ADD_TO_DB 23#include <Security/SecCertificatePriv.h> /* private */ 24 /* SecInferLabelFromX509Name() */ 25 26/* 27 * Update an existing DLDB to be CRL-capable. 28 */ 29static CSSM_RETURN crlAddCrlSchema( 30 CSSM_DL_DB_HANDLE dlDbHand) 31{ 32 return CSSM_DL_CreateRelation(dlDbHand, 33 CSSM_DL_DB_RECORD_X509_CRL, 34 "CSSM_DL_DB_RECORD_X509_CRL", 35 Security::KeychainCore::Schema::X509CrlSchemaAttributeCount, 36 Security::KeychainCore::Schema::X509CrlSchemaAttributeList, 37 Security::KeychainCore::Schema::X509CrlSchemaIndexCount, 38 Security::KeychainCore::Schema::X509CrlSchemaIndexList); 39} 40 41static void crlInferCrlLabel( 42 const CSSM_X509_NAME *x509Name, 43 CSSM_DATA *label) // not mallocd; contents are 44 // from the x509Name 45{ 46 /* use private API for common "infer label" logic */ 47 const CSSM_DATA *printValue = SecInferLabelFromX509Name(x509Name); 48 if(printValue == NULL) { 49 /* punt! */ 50 label->Data = (uint8 *)"X509 CRL"; 51 label->Length = 8; 52 } 53 else { 54 *label = *printValue; 55 } 56} 57 58/* 59 * Search extensions for specified OID, assumed to have underlying 60 * value type of uint32; returns the value and true if found. 61 */ 62static bool crlSearchNumericExtension( 63 const CSSM_X509_EXTENSIONS *extens, 64 const CSSM_OID *oid, 65 uint32 *val) 66{ 67 for(uint32 dex=0; dex<extens->numberOfExtensions; dex++) { 68 const CSSM_X509_EXTENSION *exten = &extens->extensions[dex]; 69 if(!appCompareCssmData(&exten->extnId, oid)) { 70 continue; 71 } 72 if(exten->format != CSSM_X509_DATAFORMAT_PARSED) { 73 printf("***Malformed extension\n"); 74 continue; 75 } 76 *val = *((uint32 *)exten->value.parsedValue); 77 return true; 78 } 79 return false; 80} 81 82/* 83 * Add a CRL to an existing DL/DB. 84 */ 85#define MAX_CRL_ATTRS 8 86 87CSSM_RETURN crlAddCrlToDb( 88 CSSM_DL_DB_HANDLE dlDbHand, 89 CSSM_CL_HANDLE clHand, 90 const CSSM_DATA *crl) 91{ 92 CSSM_DB_ATTRIBUTE_DATA attrs[MAX_CRL_ATTRS]; 93 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs; 94 CSSM_DB_ATTRIBUTE_DATA_PTR attr = &attrs[0]; 95 CSSM_DATA crlTypeData; 96 CSSM_DATA crlEncData; 97 CSSM_DATA printNameData; 98 CSSM_RETURN crtn; 99 CSSM_DB_UNIQUE_RECORD_PTR recordPtr; 100 CSSM_DATA_PTR issuer; // mallocd by CL 101 CSSM_DATA_PTR crlValue; // ditto 102 uint32 numFields; 103 CSSM_HANDLE result; 104 CSSM_CRL_ENCODING crlEnc = CSSM_CRL_ENCODING_DER; 105 const CSSM_X509_SIGNED_CRL *signedCrl; 106 const CSSM_X509_TBS_CERTLIST *tbsCrl; 107 CSSM_CRL_TYPE crlType; 108 CSSM_DATA thisUpdateData = {0, NULL}; 109 CSSM_DATA nextUpdateData = {0, NULL}; 110 char *thisUpdate, *nextUpdate; 111 unsigned timeLen; 112 uint32 crlNumber; 113 uint32 deltaCrlNumber; 114 CSSM_DATA crlNumberData; 115 CSSM_DATA deltaCrlNumberData; 116 bool crlNumberPresent = false; 117 bool deltaCrlPresent = false; 118 119 /* get normalized issuer name as Issuer attr */ 120 crtn = CSSM_CL_CrlGetFirstFieldValue(clHand, 121 crl, 122 &CSSMOID_X509V1IssuerName, 123 &result, 124 &numFields, 125 &issuer); 126 if(crtn) { 127 printError("CSSM_CL_CrlGetFirstFieldValue(Issuer)", crtn); 128 return crtn; 129 } 130 CSSM_CL_CrlAbortQuery(clHand, result); 131 132 /* get parsed CRL from the CL */ 133 crtn = CSSM_CL_CrlGetFirstFieldValue(clHand, 134 crl, 135 &CSSMOID_X509V2CRLSignedCrlCStruct, 136 &result, 137 &numFields, 138 &crlValue); 139 if(crtn) { 140 printError("CSSM_CL_CrlGetFirstFieldValue(Issuer)", crtn); 141 return crtn; 142 } 143 CSSM_CL_CrlAbortQuery(clHand, result); 144 if(crlValue == NULL) { 145 printf("***CSSM_CL_CrlGetFirstFieldValue: value error (1)\n"); 146 return CSSMERR_CL_INVALID_CRL_POINTER; 147 } 148 if((crlValue->Data == NULL) || 149 (crlValue->Length != sizeof(CSSM_X509_SIGNED_CRL))) { 150 printf("***CSSM_CL_CrlGetFirstFieldValue: value error (2)\n"); 151 return CSSMERR_CL_INVALID_CRL_POINTER; 152 } 153 signedCrl = (const CSSM_X509_SIGNED_CRL *)crlValue->Data; 154 tbsCrl = &signedCrl->tbsCertList; 155 156 /* CrlType inferred from version */ 157 if(tbsCrl->version.Length == 0) { 158 /* should never happen... */ 159 crlType = CSSM_CRL_TYPE_X_509v1; 160 } 161 else { 162 uint8 vers = tbsCrl->version.Data[tbsCrl->version.Length - 1]; 163 switch(vers) { 164 case 0: 165 crlType = CSSM_CRL_TYPE_X_509v1; 166 break; 167 case 1: 168 crlType = CSSM_CRL_TYPE_X_509v2; 169 break; 170 default: 171 printf("***Unknown version in CRL (%u)\n", vers); 172 crlType = CSSM_CRL_TYPE_X_509v1; 173 break; 174 } 175 } 176 crlTypeData.Data = (uint8 *)&crlType; 177 crlTypeData.Length = sizeof(CSSM_CRL_TYPE); 178 /* encoding more-or-less assumed here */ 179 crlEncData.Data = (uint8 *)&crlEnc; 180 crlEncData.Length = sizeof(CSSM_CRL_ENCODING); 181 182 /* printName inferred from issuer */ 183 crlInferCrlLabel(&tbsCrl->issuer, &printNameData); 184 185 /* cook up CSSM_TIMESTRING versions of this/next update */ 186 thisUpdate = x509TimeToCssmTimestring(&tbsCrl->thisUpdate, &timeLen); 187 if(thisUpdate == NULL) { 188 printf("***Badly formatted thisUpdate\n"); 189 } 190 else { 191 thisUpdateData.Data = (uint8 *)thisUpdate; 192 thisUpdateData.Length = timeLen; 193 } 194 nextUpdate = x509TimeToCssmTimestring(&tbsCrl->nextUpdate, &timeLen); 195 if(nextUpdate == NULL) { 196 printf("***Badly formatted nextUpdate\n"); 197 } 198 else { 199 nextUpdateData.Data = (uint8 *)nextUpdate; 200 nextUpdateData.Length = timeLen; 201 } 202 203 /* optional CrlNumber and DeltaCrlNumber */ 204 if(crlSearchNumericExtension(&tbsCrl->extensions, 205 &CSSMOID_CrlNumber, 206 &crlNumber)) { 207 crlNumberData.Data = (uint8 *)&crlNumber; 208 crlNumberData.Length = sizeof(uint32); 209 crlNumberPresent = true; 210 } 211 if(crlSearchNumericExtension(&tbsCrl->extensions, 212 &CSSMOID_DeltaCrlIndicator, 213 &deltaCrlNumber)) { 214 deltaCrlNumberData.Data = (uint8 *)&deltaCrlNumber; 215 deltaCrlNumberData.Length = sizeof(uint32); 216 deltaCrlPresent = true; 217 } 218 /* we spec six attributes, skipping alias and URI */ 219 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; 220 attr->Info.Label.AttributeName = "CrlType"; 221 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_UINT32; 222 attr->NumberOfValues = 1; 223 attr->Value = &crlTypeData; 224 attr++; 225 226 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; 227 attr->Info.Label.AttributeName = "CrlEncoding"; 228 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_UINT32; 229 attr->NumberOfValues = 1; 230 attr->Value = &crlEncData; 231 attr++; 232 233 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; 234 attr->Info.Label.AttributeName = "PrintName"; 235 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB; 236 attr->NumberOfValues = 1; 237 attr->Value = &printNameData; 238 attr++; 239 240 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; 241 attr->Info.Label.AttributeName = "Issuer"; 242 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB; 243 attr->NumberOfValues = 1; 244 attr->Value = issuer; 245 attr++; 246 247 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; 248 attr->Info.Label.AttributeName = "ThisUpdate"; 249 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB; 250 attr->NumberOfValues = 1; 251 attr->Value = &thisUpdateData; 252 attr++; 253 254 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; 255 attr->Info.Label.AttributeName = "NextUpdate"; 256 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB; 257 attr->NumberOfValues = 1; 258 attr->Value = &nextUpdateData; 259 attr++; 260 261 /* now the optional attributes */ 262 if(crlNumberPresent) { 263 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; 264 attr->Info.Label.AttributeName = "CrlNumber"; 265 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_UINT32; 266 attr->NumberOfValues = 1; 267 attr->Value = &crlNumberData; 268 attr++; 269 } 270 if(deltaCrlPresent) { 271 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; 272 attr->Info.Label.AttributeName = "DeltaCrlNumber"; 273 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_UINT32; 274 attr->NumberOfValues = 1; 275 attr->Value = &deltaCrlNumberData; 276 attr++; 277 } 278 279 recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_X509_CRL; 280 recordAttrs.SemanticInformation = 0; 281 recordAttrs.NumberOfAttributes = attr - attrs; 282 recordAttrs.AttributeData = attrs; 283 284 crtn = CSSM_DL_DataInsert(dlDbHand, 285 CSSM_DL_DB_RECORD_X509_CRL, 286 &recordAttrs, 287 crl, 288 &recordPtr); 289 if(crtn == CSSMERR_DL_INVALID_RECORDTYPE) { 290 /* gross hack of inserting this "new" schema that 291 * Keychain didn't specify */ 292 crtn = crlAddCrlSchema(dlDbHand); 293 if(crtn == CSSM_OK) { 294 /* Retry with a fully capable DLDB */ 295 crtn = CSSM_DL_DataInsert(dlDbHand, 296 CSSM_DL_DB_RECORD_X509_CRL, 297 &recordAttrs, 298 crl, 299 &recordPtr); 300 } 301 } 302 if(crtn) { 303 printError("CSSM_DL_DataInsert", crtn); 304 } 305 else { 306 CSSM_DL_FreeUniqueRecord(dlDbHand, recordPtr); 307 } 308 309 /* free all the stuff we allocated to get here */ 310 CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1IssuerName, issuer); 311 CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V2CRLSignedCrlCStruct, 312 crlValue); 313 free(thisUpdate); 314 free(nextUpdate); 315 return crtn; 316} 317 318#endif /* CRL_ADD_TO_DB */ 319