1/* Copyright (c) 2006 Apple Computer, Inc. 2 * 3 * certSerialEncodeTest.cpp 4 * 5 * Verify proper encoding of unsigned integer as a DER_encoded signed integer. 6 * Verifies Radar 4471281. 7 * 8 */ 9 10#include <utilLib/common.h> 11#include <utilLib/cspwrap.h> 12#include <security_cdsa_utils/cuFileIo.h> 13#include <clAppUtils/clutils.h> 14#include <stdlib.h> 15#include <stdio.h> 16#include <string.h> 17#include <Security/cssm.h> 18#include <Security/x509defs.h> 19#include <Security/oidsattr.h> 20#include <Security/oidscert.h> 21#include <Security/oidsalg.h> 22#include <Security/certextensions.h> 23#include <Security/cssmapple.h> 24#include <string.h> 25 26#define SUBJ_KEY_LABEL "subjectKey" 27#define ROOT_KEY_LABEL "rootKey" 28/* default key and signature algorithm */ 29#define SIG_ALG_DEFAULT CSSM_ALGID_SHA1WithRSA 30#define SIG_OID_DEFAULT CSSMOID_SHA1WithRSA 31#define KEY_ALG_DEFAULT CSSM_ALGID_RSA 32 33/* for write certs/keys option */ 34#define ROOT_CERT_FILE_NAME "ssRootCert.cer" 35#define SUBJ_CERT_FILE_NAME "ssSubjCert.cer" 36 37/* public key in ref form, TP supports this as of 1/30/02 */ 38#define PUB_KEY_IS_REF CSSM_TRUE 39 40static void usage(char **argv) 41{ 42 printf("Usage: %s [options]\n", argv[0]); 43 printf("Options:\n"); 44 printf(" w[rite certs]\n"); 45 printf(" p(ause for MallocDebug)\n"); 46 printf(" q(uiet)\n"); 47 exit(1); 48} 49 50/* 51 * RDN components 52 */ 53static CSSM_APPLE_TP_NAME_OID rootRdn[] = 54{ 55 { "Apple Computer", &CSSMOID_OrganizationName }, 56 { "The Big Cheesy Debug Root", &CSSMOID_CommonName } 57}; 58#define NUM_ROOT_NAMES (sizeof(rootRdn) / sizeof(CSSM_APPLE_TP_NAME_OID)) 59 60/* test cases */ 61typedef struct { 62 uint32 serialIn; /* --> CSSM_TP_SubmitCredRequest */ 63 CSSM_SIZE expectLen; 64 const uint8 *expect; 65} SerialNumber; 66 67/* 0x7f */ 68static const uint8 sn0_Data[1] = {0x7f}; 69static const SerialNumber sn0 = {0x7f, 1, sn0_Data }; 70 71/* 0x80 */ 72static const uint8 sn1_Data[2] = {0x00, 0x80}; 73static const SerialNumber sn1 = {0x80, 2, sn1_Data }; 74 75/* 0x7ff */ 76static const uint8 sn2_Data[2] = {0x07, 0xff}; 77static const SerialNumber sn2 = {0x7ff, 2, sn2_Data }; 78 79/* 0x80ff */ 80static const uint8 sn3_Data[3] = {0x00, 0x80, 0xff}; 81static const SerialNumber sn3 = {0x80ff, 3, sn3_Data }; 82 83/* 0xfffffff */ 84static const uint8 sn4_Data[4] = {0x0f, 0xff, 0xff, 0xff}; 85static const SerialNumber sn4 = {0xfffffff, 4, sn4_Data }; 86 87/* 0x0fffffff */ 88static const uint8 sn5_Data[4] = {0x0f, 0xff, 0xff, 0xff}; 89static const SerialNumber sn5 = {0x0fffffff, 4, sn5_Data }; 90 91/* 0x80000000 */ 92static const uint8 sn6_Data[5] = {0x00, 0x80, 0x00, 0x00, 0x00}; 93static const SerialNumber sn6 = {0x80000000, 5, sn6_Data }; 94 95static const SerialNumber *serialNumbers[] = { 96 &sn0, &sn1, &sn2, &sn3, &sn4, &sn5, &sn6 97}; 98#define NUM_SERIAL_NUMS (sizeof(serialNumbers) / sizeof(serialNumbers[0])) 99 100static int doTest( 101 CSSM_CL_HANDLE clHand, // CL handle 102 CSSM_CSP_HANDLE cspHand, // CSP handle 103 CSSM_TP_HANDLE tpHand, // TP handle 104 CSSM_KEY_PTR subjPubKey, 105 CSSM_KEY_PTR signerPrivKey, 106 uint32 serialNumIn, 107 CSSM_SIZE serialNumExpLen, 108 const uint8 *serialNumExp, 109 CSSM_BOOL quiet, 110 CSSM_BOOL writeBlobs) 111{ 112 CSSM_DATA refId; // mallocd by CSSM_TP_SubmitCredRequest 113 CSSM_APPLE_TP_CERT_REQUEST certReq; 114 CSSM_TP_REQUEST_SET reqSet; 115 sint32 estTime; 116 CSSM_BOOL confirmRequired; 117 CSSM_TP_RESULT_SET_PTR resultSet; 118 CSSM_ENCODED_CERT *encCert; 119 CSSM_TP_CALLERAUTH_CONTEXT CallerAuthContext; 120 CSSM_FIELD policyId; 121 CSSM_RETURN crtn; 122 CSSM_DATA *signedRootCert; 123 int ourRtn = 0; 124 CSSM_DATA_PTR foundSerial = NULL; 125 CSSM_HANDLE resultHand = 0; 126 uint32 numFields; 127 128 /* certReq for root */ 129 memset(&certReq, 0, sizeof(CSSM_APPLE_TP_CERT_REQUEST)); 130 certReq.cspHand = cspHand; 131 certReq.clHand = clHand; 132 certReq.serialNumber = serialNumIn; 133 certReq.numSubjectNames = NUM_ROOT_NAMES; 134 certReq.subjectNames = rootRdn; 135 certReq.numIssuerNames = 0; 136 certReq.issuerNames = NULL; 137 certReq.certPublicKey = subjPubKey; 138 certReq.issuerPrivateKey = signerPrivKey; 139 certReq.signatureAlg = CSSM_ALGID_SHA1WithRSA; 140 certReq.signatureOid = CSSMOID_SHA1WithRSA; 141 certReq.notBefore = 0; // now 142 certReq.notAfter = 10000; // seconds from now 143 certReq.numExtensions = 0; 144 certReq.extensions = NULL; 145 146 reqSet.NumberOfRequests = 1; 147 reqSet.Requests = &certReq; 148 149 /* a big CSSM_TP_CALLERAUTH_CONTEXT just to specify an OID */ 150 memset(&CallerAuthContext, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT)); 151 memset(&policyId, 0, sizeof(CSSM_FIELD)); 152 policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN; 153 CallerAuthContext.Policy.NumberOfPolicyIds = 1; 154 CallerAuthContext.Policy.PolicyIds = &policyId; 155 156 /* generate root cert */ 157 if(!quiet) { 158 printf("Creating root cert...\n"); 159 } 160 crtn = CSSM_TP_SubmitCredRequest(tpHand, 161 NULL, // PreferredAuthority 162 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, 163 &reqSet, 164 &CallerAuthContext, 165 &estTime, 166 &refId); 167 if(crtn) { 168 printError("CSSM_TP_SubmitCredRequest", crtn); 169 ourRtn = -1; 170 goto errOut; 171 } 172 crtn = CSSM_TP_RetrieveCredResult(tpHand, 173 &refId, 174 NULL, // CallerAuthCredentials 175 &estTime, 176 &confirmRequired, 177 &resultSet); 178 if(crtn) { 179 printError("CSSM_TP_RetrieveCredResult", crtn); 180 ourRtn = -1; 181 goto errOut; 182 } 183 if(resultSet == NULL) { 184 printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n"); 185 ourRtn = -1; 186 goto errOut; 187 } 188 encCert = (CSSM_ENCODED_CERT *)resultSet->Results; 189 signedRootCert = &encCert->CertBlob; 190 if(writeBlobs) { 191 writeFile(ROOT_CERT_FILE_NAME, signedRootCert->Data, signedRootCert->Length); 192 printf("...wrote %lu bytes to %s\n", signedRootCert->Length, 193 ROOT_CERT_FILE_NAME); 194 } 195 196 /* make sure it self-verifies */ 197 crtn = CSSM_CL_CertVerify(clHand, 0 /* CCHandle */, 198 signedRootCert, signedRootCert, 199 NULL, 0); 200 if(crtn) { 201 cssmPerror("CSSM_CL_CertVerify", crtn); 202 printf("***Created cert does not self-verify\n"); 203 ourRtn = -1; 204 goto errOut; 205 } 206 207 /* extract the field we're interested in verifying */ 208 crtn = CSSM_CL_CertGetFirstFieldValue(clHand, signedRootCert, 209 &CSSMOID_X509V1SerialNumber, &resultHand, &numFields, &foundSerial); 210 if(crtn) { 211 cssmPerror("CSSM_CL_CertGetFirstFieldValue(serialNumber)", crtn); 212 printf("***Can't obtain serial number\n"); 213 ourRtn = -1; 214 goto errOut; 215 } 216 CSSM_CL_CertAbortQuery(clHand, resultHand); 217 if(foundSerial->Length != serialNumExpLen) { 218 printf("***expected serialNumber len 0x%lu, got 0x%lu\n", 219 (unsigned long)serialNumExpLen, (unsigned long)foundSerial->Length); 220 ourRtn = -1; 221 goto errOut; 222 } 223 for(unsigned dex=0; dex<serialNumExpLen; dex++) { 224 if(foundSerial->Data[dex] != serialNumExp[dex]) { 225 printf("***SerialNumber mismatch at index %u: exp %02X got %02X\n", 226 dex, (unsigned)serialNumExp[dex], 227 (unsigned)foundSerial->Data[dex]); 228 ourRtn = -1; 229 } 230 } 231 /* free retrieved serial number and the result set itself */ 232 CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1SerialNumber, foundSerial); 233 CSSM_FREE(signedRootCert->Data); 234 CSSM_FREE(encCert); 235 CSSM_FREE(resultSet); 236 /* Per the spec, this is supposed to be Opaque to us and the TP is supposed to free 237 * it when it goes out of scope...but libsecurity_keychains's 238 * CertificateRequest::submitDotMac() frees this...that would have to change 239 * in order for the TP to free this properly. Someday maybe. No big deal. 240 */ 241 CSSM_FREE(refId.Data); 242errOut: 243 return ourRtn; 244} 245 246int main(int argc, char **argv) 247{ 248 CSSM_CL_HANDLE clHand; // CL handle 249 CSSM_CSP_HANDLE cspHand; // CSP handle 250 CSSM_TP_HANDLE tpHand; // TP handle 251 CSSM_KEY rootPubKey; // root's RSA public key blob 252 CSSM_KEY rootPrivKey; // root's RSA private key - ref format 253 CSSM_RETURN crtn; 254 int arg; 255 unsigned dex; 256 int ourRtn = 0; 257 uint32 keySizeInBits = 512; 258 CSSM_BOOL doPause = CSSM_FALSE; 259 260 /* user-spec'd variables */ 261 CSSM_BOOL writeBlobs = CSSM_FALSE; 262 CSSM_BOOL quiet = CSSM_FALSE; 263 264 for(arg=1; arg<argc; arg++) { 265 switch(argv[arg][0]) { 266 case 'w': 267 writeBlobs = CSSM_TRUE; 268 break; 269 case 'q': 270 quiet = CSSM_TRUE; 271 break; 272 case 'p': 273 doPause = CSSM_TRUE; 274 break; 275 default: 276 usage(argv); 277 } 278 } 279 280 testStartBanner("certSerialEncodeTest", argc, argv); 281 282 283 /* connect to CL, TP, and CSP */ 284 clHand = clStartup(); 285 if(clHand == 0) { 286 return -1; 287 } 288 tpHand = tpStartup(); 289 if(tpHand == 0) { 290 return -1; 291 } 292 cspHand = cspStartup(); 293 if(cspHand == 0) { 294 return -1; 295 } 296 297 /* cook up key pair for self-signed cert */ 298 crtn = cspGenKeyPair(cspHand, 299 CSSM_ALGID_RSA, 300 ROOT_KEY_LABEL, 301 strlen(ROOT_KEY_LABEL), 302 keySizeInBits, 303 &rootPubKey, 304 CSSM_FALSE, // pubIsRef - should work both ways, but not yet 305 CSSM_KEYUSE_VERIFY, 306 CSSM_KEYBLOB_RAW_FORMAT_NONE, 307 &rootPrivKey, 308 writeBlobs ? CSSM_FALSE : CSSM_TRUE, // privIsRef 309 CSSM_KEYUSE_SIGN, 310 CSSM_KEYBLOB_RAW_FORMAT_NONE, 311 CSSM_FALSE); 312 if(crtn) { 313 ourRtn = -1; 314 goto abort; 315 } 316 317 for(dex=0; dex<NUM_SERIAL_NUMS; dex++) { 318 const SerialNumber *sn = serialNumbers[dex]; 319 if(!quiet) { 320 printf("...testing serial number 0x%lx\n", (unsigned long)sn->serialIn); 321 } 322 ourRtn = doTest(clHand, cspHand, tpHand, 323 &rootPubKey, &rootPrivKey, 324 sn->serialIn, sn->expectLen, sn->expect, 325 quiet, writeBlobs); 326 if(ourRtn) { 327 break; 328 } 329 if(doPause) { 330 fpurge(stdin); 331 printf("Pausing for MallocDebug. a to abort, anything else to continue: "); 332 if(getchar() == 'a') { 333 break; 334 } 335 } 336 } 337 338 cspFreeKey(cspHand, &rootPubKey); 339 cspFreeKey(cspHand, &rootPrivKey); 340 341abort: 342 if(cspHand != 0) { 343 CSSM_ModuleDetach(cspHand); 344 } 345 if(clHand != 0) { 346 CSSM_ModuleDetach(clHand); 347 } 348 if(tpHand != 0) { 349 CSSM_ModuleDetach(tpHand); 350 } 351 352 if((ourRtn == 0) && !quiet) { 353 printf("certSerialEncodeTest test succeeded\n"); 354 } 355 return ourRtn; 356} 357 358 359