1/* Copyright (c) 1998-2003,2005-2006 Apple Computer, Inc. 2 * 3 * signerAndSubjSsl.c 4 * 5 * Create two certs - a root, and a subject cert signed by the root. 6 * Includes subjectAltName extension for leaf cert. 7 * This version uses CSSM_TP_SubmitCredRequest to create the certs. 8 * 9 */ 10 11#include <utilLib/common.h> 12#include <utilLib/cspwrap.h> 13#include <security_cdsa_utils/cuFileIo.h> 14#include <clAppUtils/clutils.h> 15#include <stdlib.h> 16#include <stdio.h> 17#include <string.h> 18#include <Security/cssm.h> 19#include <Security/x509defs.h> 20#include <Security/oidsattr.h> 21#include <Security/oidscert.h> 22#include <Security/oidsalg.h> 23#include <Security/certextensions.h> 24#include <Security/cssmapple.h> 25#include <string.h> 26 27/* key labels */ 28#define SUBJ_KEY_LABEL "subjectKey" 29#define ROOT_KEY_LABEL "rootKey" 30 31/* default key and signature algorithm */ 32#define SIG_ALG_DEFAULT CSSM_ALGID_SHA1WithRSA 33#define SIG_OID_DEFAULT CSSMOID_SHA1WithRSA 34#define KEY_ALG_DEFAULT CSSM_ALGID_RSA 35 36/* for write certs option */ 37#define ROOT_CERT_FILE_NAME "ssRootCert.der" 38#define SUBJ_CERT_FILE_NAME "ssSubjCert.der" 39 40/* public key in ref form, TP supports this as of 1/30/02 */ 41#define PUB_KEY_IS_REF CSSM_TRUE 42 43static void usage(char **argv) 44{ 45 printf("Usage: %s [options]\n", argv[0]); 46 printf("Options:\n"); 47 printf(" i=IP_Address for subjectAltName\n"); 48 printf(" d=dnsName for subjectAltName\n"); 49 printf(" k=keySizeInBits\n"); 50 printf(" q(uiet)\n"); 51 exit(1); 52} 53 54/* 55 * RDN components for root, subject 56 */ 57CSSM_APPLE_TP_NAME_OID rootRdn[] = 58{ 59 { "Apple Computer", &CSSMOID_OrganizationName }, 60 { "The Big Cheese", &CSSMOID_Title } 61}; 62#define NUM_ROOT_NAMES (sizeof(rootRdn) / sizeof(CSSM_APPLE_TP_NAME_OID)) 63 64CSSM_APPLE_TP_NAME_OID subjRdn[] = 65{ 66 { "Apple Computer", &CSSMOID_OrganizationName }, 67 { "something.org", &CSSMOID_CommonName } 68}; 69#define NUM_SUBJ_NAMES (sizeof(subjRdn) / sizeof(CSSM_APPLE_TP_NAME_OID)) 70 71/* 72 * Convert a string containing a dotted IP address to 4 bytes. 73 * Returns nonzero on error. 74 */ 75static int convertIp( 76 const char *str, 77 uint8 *buf) 78{ 79 char cbuf[4]; 80 for(unsigned dex=0; dex<3; dex++) { 81 char *nextDot = strchr(str, '.'); 82 if(nextDot == NULL) { 83 return 1; 84 } 85 memmove(cbuf, str, nextDot - str); 86 *buf = atoi(cbuf); 87 buf++; // next out char 88 str = nextDot + 1; // next in char after dot 89 90 } 91 /* str points to last char */ 92 if(str == NULL) { 93 return 1; 94 } 95 *buf = atoi(str); 96 return 0; 97} 98 99int main(int argc, char **argv) 100{ 101 CSSM_CL_HANDLE clHand; // CL handle 102 CSSM_CSP_HANDLE cspHand; // CSP handle 103 CSSM_TP_HANDLE tpHand; // TP handle 104 CSSM_DATA signedRootCert; // from CSSM_CL_CertSign 105 CSSM_DATA signedSubjCert; // from CSSM_CL_CertSign 106 CSSM_KEY subjPubKey; // subject's RSA public key blob 107 CSSM_KEY subjPrivKey; // subject's RSA private key - ref format 108 CSSM_KEY rootPubKey; // root's RSA public key blob 109 CSSM_KEY rootPrivKey; // root's RSA private key - ref format 110 CSSM_RETURN crtn; 111 int arg; 112 unsigned errorCount = 0; 113 CSSM_DATA refId; // mallocd by CSSM_TP_SubmitCredRequest 114 CSSM_APPLE_TP_CERT_REQUEST certReq; 115 CSSM_TP_REQUEST_SET reqSet; 116 sint32 estTime; 117 CSSM_BOOL confirmRequired; 118 CSSM_TP_RESULT_SET_PTR resultSet; 119 CSSM_ENCODED_CERT *encCert; 120 CSSM_TP_CALLERAUTH_CONTEXT CallerAuthContext; 121 CSSM_FIELD policyId; 122 CE_GeneralNames genNames; 123 CE_GeneralName genName; 124 uint8 ipNameBuf[4]; 125 126 /* user-spec'd variables */ 127 CSSM_ALGORITHMS keyAlg = KEY_ALG_DEFAULT; 128 CSSM_ALGORITHMS sigAlg = SIG_ALG_DEFAULT; 129 CSSM_OID sigOid = SIG_OID_DEFAULT; 130 uint32 keySizeInBits = CSP_KEY_SIZE_DEFAULT; 131 char *ipAddrs = NULL; 132 char *dnsName = NULL; 133 CSSM_BOOL quiet = CSSM_FALSE; 134 135 /* 136 * Two extensions. Subject has two (KeyUsage and possibly 137 * subjectAltName); root has KeyUsage and BasicConstraints. 138 */ 139 CE_DataAndType rootExts[2]; 140 CE_DataAndType leafExts[2]; 141 unsigned numLeafExts; 142 143 for(arg=1; arg<argc; arg++) { 144 char *argp = argv[arg]; 145 switch(argp[0]) { 146 case 'k': 147 keySizeInBits = atoi(&argp[2]); 148 break; 149 case 'i': 150 ipAddrs = &argp[2]; 151 break; 152 case 'd': 153 dnsName = &argp[2]; 154 break; 155 case 'q': 156 quiet = CSSM_TRUE; 157 break; 158 default: 159 usage(argv); 160 } 161 } 162 163 if(ipAddrs && dnsName) { 164 printf("Max of one of {ipAddrs, dnsName} at a time, please.\n"); 165 usage(argv); 166 } 167 if(ipAddrs) { 168 if(convertIp(ipAddrs, ipNameBuf)) { 169 printf("**Malformed IP address. Aborting.\n"); 170 exit(1); 171 } 172 } 173 174 /* connect to CL, TP, and CSP */ 175 clHand = clStartup(); 176 if(clHand == 0) { 177 return 0; 178 } 179 tpHand = tpStartup(); 180 if(tpHand == 0) { 181 return 0; 182 } 183 cspHand = cspStartup(); 184 if(cspHand == 0) { 185 return 0; 186 } 187 188 /* subsequent errors to abort: to detach */ 189 190 /* cook up an RSA key pair for the subject */ 191 crtn = cspGenKeyPair(cspHand, 192 keyAlg, 193 SUBJ_KEY_LABEL, 194 strlen(SUBJ_KEY_LABEL), 195 keySizeInBits, 196 &subjPubKey, 197 #if PUB_KEY_IS_REF 198 CSSM_TRUE, 199 #else 200 CSSM_FALSE, // pubIsRef - should work both ways, but not yet 201 #endif 202 CSSM_KEYUSE_VERIFY, 203 CSSM_KEYBLOB_RAW_FORMAT_NONE, 204 &subjPrivKey, 205 CSSM_TRUE, // privIsRef - doesn't matter 206 CSSM_KEYUSE_SIGN, 207 CSSM_KEYBLOB_RAW_FORMAT_NONE, 208 CSSM_FALSE); 209 if(crtn) { 210 errorCount++; 211 goto abort; 212 } 213 214 /* and the root */ 215 crtn = cspGenKeyPair(cspHand, 216 keyAlg, 217 ROOT_KEY_LABEL, 218 strlen(ROOT_KEY_LABEL), 219 keySizeInBits, 220 &rootPubKey, 221 CSSM_FALSE, // pubIsRef - should work both ways, but not yet 222 CSSM_KEYUSE_VERIFY, 223 CSSM_KEYBLOB_RAW_FORMAT_NONE, 224 &rootPrivKey, 225 CSSM_TRUE, // privIsRef - doesn't matter 226 CSSM_KEYUSE_SIGN, 227 CSSM_KEYBLOB_RAW_FORMAT_NONE, 228 CSSM_FALSE); 229 if(crtn) { 230 errorCount++; 231 goto abort; 232 } 233 234 /* A KeyUsage extension for both certs */ 235 rootExts[0].type = DT_KeyUsage; 236 rootExts[0].critical = CSSM_FALSE; 237 rootExts[0].extension.keyUsage = 238 CE_KU_DigitalSignature | CE_KU_KeyCertSign; 239 240 leafExts[0].type = DT_KeyUsage; 241 leafExts[0].critical = CSSM_FALSE; 242 leafExts[0].extension.keyUsage = CE_KU_DigitalSignature; 243 244 /* BasicConstraints for root only */ 245 rootExts[1].type = DT_BasicConstraints; 246 rootExts[1].critical = CSSM_TRUE; 247 rootExts[1].extension.basicConstraints.cA = CSSM_TRUE; 248 rootExts[1].extension.basicConstraints.pathLenConstraintPresent = 249 CSSM_TRUE; 250 rootExts[1].extension.basicConstraints.pathLenConstraint = 2; 251 252 /* possible subjectAltName for leaf */ 253 numLeafExts = 1; 254 if(ipAddrs || dnsName) { 255 numLeafExts++; 256 leafExts[1].type = DT_SubjectAltName; 257 leafExts[1].critical = CSSM_TRUE; 258 259 genName.berEncoded = CSSM_FALSE; 260 if(ipAddrs) { 261 genName.name.Data = (uint8 *)ipNameBuf; 262 genName.name.Length = 4; 263 genName.nameType = GNT_IPAddress; 264 } 265 else { 266 genName.name.Data = (uint8 *)dnsName; 267 genName.nameType = GNT_DNSName; 268 genName.name.Length = strlen(dnsName); 269 } 270 genNames.numNames = 1; 271 genNames.generalName = &genName; 272 leafExts[1].extension.subjectAltName = genNames; 273 } 274 275 /* certReq for root */ 276 memset(&certReq, 0, sizeof(CSSM_APPLE_TP_CERT_REQUEST)); 277 certReq.cspHand = cspHand; 278 certReq.clHand = clHand; 279 certReq.serialNumber = 0x12345678; 280 certReq.numSubjectNames = NUM_ROOT_NAMES; 281 certReq.subjectNames = rootRdn; 282 certReq.numIssuerNames = 0; 283 certReq.issuerNames = NULL; 284 certReq.certPublicKey = &rootPubKey; 285 certReq.issuerPrivateKey = &rootPrivKey; 286 certReq.signatureAlg = sigAlg; 287 certReq.signatureOid = sigOid; 288 certReq.notBefore = 0; // now 289 certReq.notAfter = 10000; // seconds from now 290 certReq.numExtensions = 2; 291 certReq.extensions = rootExts; 292 293 reqSet.NumberOfRequests = 1; 294 reqSet.Requests = &certReq; 295 296 /* a big CSSM_TP_CALLERAUTH_CONTEXT just to specify an OID */ 297 memset(&CallerAuthContext, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT)); 298 memset(&policyId, 0, sizeof(CSSM_FIELD)); 299 policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN; 300 CallerAuthContext.Policy.NumberOfPolicyIds = 1; 301 CallerAuthContext.Policy.PolicyIds = &policyId; 302 303 /* generate root cert */ 304 crtn = CSSM_TP_SubmitCredRequest(tpHand, 305 NULL, // PreferredAuthority 306 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, 307 &reqSet, 308 &CallerAuthContext, 309 &estTime, 310 &refId); 311 if(crtn) { 312 printError("CSSM_TP_SubmitCredRequest", crtn); 313 errorCount++; 314 goto abort; 315 } 316 crtn = CSSM_TP_RetrieveCredResult(tpHand, 317 &refId, 318 NULL, // CallerAuthCredentials 319 &estTime, 320 &confirmRequired, 321 &resultSet); 322 if(crtn) { 323 printError("CSSM_TP_RetrieveCredResult", crtn); 324 errorCount++; 325 goto abort; 326 } 327 if(resultSet == NULL) { 328 printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n"); 329 errorCount++; 330 goto abort; 331 } 332 encCert = (CSSM_ENCODED_CERT *)resultSet->Results; 333 signedRootCert = encCert->CertBlob; 334 335 writeFile(ROOT_CERT_FILE_NAME, signedRootCert.Data, 336 signedRootCert.Length); 337 if(!quiet) { 338 printf("...wrote %lu bytes to %s\n", signedRootCert.Length, 339 ROOT_CERT_FILE_NAME); 340 } 341 342 /* now a subject cert signed by the root cert */ 343 certReq.serialNumber = 0x8765; 344 certReq.numSubjectNames = NUM_SUBJ_NAMES; 345 certReq.subjectNames = subjRdn; 346 certReq.numIssuerNames = NUM_ROOT_NAMES; 347 certReq.issuerNames = rootRdn; 348 certReq.certPublicKey = &subjPubKey; 349 certReq.issuerPrivateKey = &rootPrivKey; 350 certReq.numExtensions = numLeafExts; 351 certReq.extensions = leafExts; 352 353 crtn = CSSM_TP_SubmitCredRequest(tpHand, 354 NULL, // PreferredAuthority 355 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, 356 &reqSet, 357 &CallerAuthContext, 358 &estTime, 359 &refId); 360 if(crtn) { 361 printError("CSSM_TP_SubmitCredRequest (2)", crtn); 362 errorCount++; 363 goto abort; 364 } 365 crtn = CSSM_TP_RetrieveCredResult(tpHand, 366 &refId, 367 NULL, // CallerAuthCredentials 368 &estTime, 369 &confirmRequired, 370 &resultSet); // leaks..... 371 if(crtn) { 372 printError("CSSM_TP_RetrieveCredResult (2)", crtn); 373 errorCount++; 374 goto abort; 375 } 376 if(resultSet == NULL) { 377 printf("***CSSM_TP_RetrieveCredResult (2) returned NULL result set.\n"); 378 errorCount++; 379 goto abort; 380 } 381 encCert = (CSSM_ENCODED_CERT *)resultSet->Results; 382 signedSubjCert = encCert->CertBlob; 383 384 writeFile(SUBJ_CERT_FILE_NAME, signedSubjCert.Data, 385 signedSubjCert.Length); 386 if(!quiet) { 387 printf("...wrote %lu bytes to %s\n", signedSubjCert.Length, 388 SUBJ_CERT_FILE_NAME); 389 } 390 391 /* free/delete certs and keys */ 392 appFreeCssmData(&signedSubjCert, CSSM_FALSE); 393 appFreeCssmData(&signedRootCert, CSSM_FALSE); 394 395 cspFreeKey(cspHand, &rootPubKey); 396 cspFreeKey(cspHand, &subjPubKey); 397 398abort: 399 if(cspHand != 0) { 400 CSSM_ModuleDetach(cspHand); 401 } 402 if(clHand != 0) { 403 CSSM_ModuleDetach(clHand); 404 } 405 if(tpHand != 0) { 406 CSSM_ModuleDetach(tpHand); 407 } 408 409 return 0; 410} 411 412 413