2  * Copyright (c) 2003-2004,2006,2008,2012,2014 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  26 #include "key_create.h" 
  28 #include "keychain_utilities.h" 
  29 #include "security_tool.h" 
  31 #include <CoreFoundation/CFDateFormatter.h> 
  32 #include <CoreFoundation/CFString.h> 
  33 #include <Security/SecAccess.h> 
  34 #include <Security/SecKey.h> 
  35 #include <Security/SecKeychainItem.h> 
  36 #include <Security/SecTrustedApplication.h> 
  44 do_key_create_pair(const char *keychainName
, SecAccessRef access
, CSSM_ALGORITHMS algorithm
, uint32 keySizeInBits
, CFAbsoluteTime from_time
, CFAbsoluteTime to_time
, Boolean print_hash
) 
  46         SecKeychainRef keychain 
= NULL
; 
  49         CSSM_CC_HANDLE contextHandle 
= 0; 
  50         CSSM_KEYUSE publicKeyUsage 
= CSSM_KEYUSE_ENCRYPT 
| CSSM_KEYUSE_VERIFY 
| CSSM_KEYUSE_WRAP 
| CSSM_KEYUSE_DERIVE
; 
  51         uint32 publicKeyAttr 
= CSSM_KEYATTR_PERMANENT 
| CSSM_KEYATTR_EXTRACTABLE
; 
  52         CSSM_KEYUSE privateKeyUsage 
= CSSM_KEYUSE_DECRYPT 
| CSSM_KEYUSE_SIGN 
| CSSM_KEYUSE_UNWRAP 
| CSSM_KEYUSE_DERIVE
; 
  53         uint32 privateKeyAttr 
= CSSM_KEYATTR_PERMANENT 
| CSSM_KEYATTR_SENSITIVE 
| CSSM_KEYATTR_EXTRACTABLE
; 
  54         SecKeyRef publicKey 
= NULL
; 
  55         SecKeyRef privateKey 
= NULL
; 
  56         SecKeychainAttributeList 
*attrList 
= NULL
; 
  60                 keychain 
= keychain_open(keychainName
); 
  68         status 
= SecKeyCreatePair(keychain
, algorithm
, keySizeInBits
, contextHandle
, 
  78                 sec_error("SecKeyCreatePair %s: %s", keychainName 
? keychainName 
: "<NULL>", sec_errstr(status
)); 
  85                 SecItemClass itemClass 
= 0; 
  86                 UInt32 tag 
= 0x00000006; 
  87                 UInt32 format 
= CSSM_DB_ATTRIBUTE_FORMAT_BLOB
; 
  88                 SecKeychainAttributeInfo info 
= { 1, &tag
, &format 
}; 
  90                 status 
= SecKeychainItemCopyAttributesAndData((SecKeychainItemRef
)privateKey
, &info
, &itemClass
, &attrList
, NULL
, NULL
); 
  93                         sec_perror("SecKeychainItemCopyAttributesAndData", status
); 
  98                 if (info
.count 
!= attrList
->count
) 
 100                         sec_error("info count: %ld != attribute count: %ld", info
.count
, attrList
->count
); 
 105                 if (tag 
!= attrList
->attr
[0].tag
) 
 107                         sec_error("attribute info tag: %ld != attribute tag: %ld", tag
, attrList
->attr
[0].tag
); 
 112                 print_buffer_pem(stdout
, "PUBLIC KEY HASH", attrList
->attr
[0].length
, attrList
->attr
[0].data
); 
 118                 status 
= SecKeychainItemFreeAttributesAndData(attrList
, NULL
); 
 120                         sec_perror("SecKeychainItemFreeAttributesAndData", status
); 
 126                 CFRelease(publicKey
); 
 128                 CFRelease(privateKey
); 
 134 parse_algorithm(const char *name
, CSSM_ALGORITHMS 
*algorithm
) 
 136         size_t len 
= strlen(name
); 
 138         if (!strncmp("rsa", name
, len
)) 
 139                 *algorithm 
= CSSM_ALGID_RSA
; 
 140         else if (!strncmp("dsa", name
, len
)) 
 141                 *algorithm 
= CSSM_ALGID_DSA
; 
 142         else if (!strncmp("dh", name
, len
)) 
 143                 *algorithm 
= CSSM_ALGID_DH
; 
 144         else if (!strncmp("fee", name
, len
)) 
 145                 *algorithm 
= CSSM_ALGID_FEE
; 
 148                 sec_error("Invalid algorithm: %s", name
); 
 149                 return SHOW_USAGE_MESSAGE
; 
 156 parse_time(const char *time
, CFAbsoluteTime 
*ptime
) 
 158     CFDateFormatterRef formatter 
= CFDateFormatterCreate(NULL
, NULL
, kCFDateFormatterShortStyle
, kCFDateFormatterShortStyle
); 
 159         CFStringRef time_string 
= CFStringCreateWithCString(NULL
, time
, kCFStringEncodingUTF8
); 
 161         if (!CFDateFormatterGetAbsoluteTimeFromString(formatter
, time_string
, NULL
, ptime
)) 
 163                 sec_error("%s is not a valid date", time
); 
 167         CFRelease(formatter
); 
 169         CFRelease(time_string
); 
 174 key_create_pair(int argc
, char * const *argv
) 
 176         const char *keychainName 
= NULL
; 
 177         CSSM_ALGORITHMS algorithm 
= CSSM_ALGID_RSA
; 
 178         uint32 keySizeInBits 
= 512; 
 181         Boolean always_allow 
= FALSE
; 
 182         Boolean print_hash 
= FALSE
; 
 183         CFAbsoluteTime from_time 
= 0.0, to_time 
= 0.0; 
 185         SecAccessRef access 
= NULL
; 
 186         CFMutableArrayRef trusted_list 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 187         CFStringRef description 
= NULL
; 
 190     { "create-keypair", key_create_pair, 
 191           "[-a alg] [-s size] [-f date] [-t date] [-d days] [-k keychain] [-A|-T appPath] description\n" 
 192           "    -a  Use alg as the algorithm, can be rsa, dh, dsa or fee (default rsa)\n" 
 193           "    -s  Specify the keysize in bits (default 512)\n" 
 194           "    -f  Make a key valid from the specified date\n" 
 195           "    -t  Make a key valid to the specified date\n" 
 196           "    -d  Make a key valid for the number of days specified from now\n" 
 197           "    -k  Use the specified keychain rather than the default\n" 
 198           "    -H  Print the public key hash attribute\n" 
 199           "    -A  Allow any application to access without warning\n" 
 200           "    -T  Allow the application specified to access without warning (multiple -T options are allowed)\n" 
 201           "If no options are provided, ask the user interactively.", 
 204     while ((ch 
= getopt(argc
, argv
, "a:s:f:t:d:k:AHT:h")) != -1) 
 209                         result 
= parse_algorithm(optarg
, &algorithm
); 
 214                         keySizeInBits 
= atoi(optarg
); 
 217                         keychainName 
= optarg
; 
 229                                 SecTrustedApplicationRef app 
= NULL
; 
 230                                 status 
= SecTrustedApplicationCreateFromPath(optarg
, &app
); 
 233                                         sec_error("SecTrustedApplicationCreateFromPath %s: %s", optarg
, sec_errstr(status
)); 
 238                                 CFArrayAppendValue(trusted_list
, app
); 
 244                          result 
= parse_time(optarg
, &from_time
); 
 249                          result 
= parse_time(optarg
, &to_time
); 
 260                         from_time 
= CFAbsoluteTimeGetCurrent(); 
 261                         to_time 
= from_time 
+ days 
* 86400.0; 
 265                         return SHOW_USAGE_MESSAGE
; 
 274                 if (*argv
[0] == '\0') 
 279                 description  
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
); 
 282                 return SHOW_USAGE_MESSAGE
; 
 284                 description 
= CFStringCreateWithCString(NULL
, "<key>", kCFStringEncodingUTF8
); 
 288                 status 
= SecAccessCreate(description
, NULL
, &access
); 
 291                         sec_perror("SecAccessCreate", status
); 
 297                 status 
= SecAccessCreate(description
, trusted_list
, &access
); 
 300                         sec_perror("SecAccessCreate", status
); 
 308         result 
= do_key_create_pair(keychainName
, access
, algorithm
, keySizeInBits
, from_time
, to_time
, print_hash
); 
 312                 CFRelease(description
); 
 314                 CFRelease(trusted_list
); 
 324         CSSM_TP_HANDLE          tpHand
,                         // eventually, a SecKeychainRef 
 325         CSSM_CL_HANDLE          clHand
, 
 326         CSSM_CSP_HANDLE         cspHand
, 
 327         SecKeyRef                       subjPubKey
, 
 328         SecKeyRef                       signerPrivKey
, 
 329         CSSM_ALGORITHMS         sigAlg
, 
 330         const CSSM_OID          
*sigOid
, 
 332          * Issuer's RDN is obtained from the issuer cert, if present, or is 
 333          * assumed to be the same as the subject name (i.e., we're creating 
 334          * a self-signed root cert). 
 336         CSSM_BOOL                       useAllDefaults
, 
 337         CSSM_DATA_PTR           csrData
)                        // CSR: mallocd and RETURNED 
 339         CE_DataAndType                          exts
[2]; 
 340         CE_DataAndType                          
*extp 
= exts
; 
 343         CSSM_DATA                                       refId
;          // mallocd by CSSM_TP_SubmitCredRequest 
 344         CSSM_APPLE_TP_CERT_REQUEST      certReq
; 
 345         CSSM_TP_REQUEST_SET                     reqSet
; 
 347         CSSM_BOOL                                       confirmRequired
; 
 348         CSSM_TP_RESULT_SET_PTR          resultSet
; 
 349         CSSM_ENCODED_CERT                       
*encCert
; 
 350         CSSM_APPLE_TP_NAME_OID          subjectNames
[MAX_NAMES
]; 
 352         CSSM_TP_CALLERAUTH_CONTEXT      CallerAuthContext
; 
 355         /* Note a lot of the CSSM_APPLE_TP_CERT_REQUEST fields are not 
 356          * used for the createCsr option, but we'll fill in as much as is practical 
 361         char challengeBuf
[400]; 
 363                 strcpy(challengeBuf
, ZDEF_CHALLENGE
); 
 367                         getStringWithPrompt("Enter challenge string: ", 
 368                                 challengeBuf
, sizeof(challengeBuf
)); 
 369                         if(challengeBuf
[0] != '\0') { 
 374         certReq
.challengeString 
= challengeBuf
; 
 376         /* name array, get from user. */ 
 378                 subjectNames
[0].string  
= ZDEF_COMMON_NAME
; 
 379                 subjectNames
[0].oid     
= &CSSMOID_CommonName
; 
 380                 subjectNames
[1].string  
= ZDEF_ORG_NAME
; 
 381                 subjectNames
[1].oid     
= &CSSMOID_OrganizationName
; 
 382                 subjectNames
[2].string  
= ZDEF_COUNTRY
; 
 383                 subjectNames
[2].oid     
= &CSSMOID_CountryName
; 
 384                 subjectNames
[3].string  
= ZDEF_STATE
; 
 385                 subjectNames
[3].oid     
= &CSSMOID_StateProvinceName
; 
 389                 getNameOids(subjectNames
, &numNames
); 
 393         certReq
.cspHand 
= cspHand
; 
 394         certReq
.clHand 
= clHand
; 
 395         certReq
.serialNumber 
= 0x12345678;              // TBD - random? From user? 
 396         certReq
.numSubjectNames 
= numNames
; 
 397         certReq
.subjectNames 
= subjectNames
; 
 399         /* TBD - if we're passed in a signing cert, certReq.issuerNameX509 will 
 400          * be obtained from that cert. For now we specify "self-signed" cert 
 401          * by not providing an issuer name at all. */ 
 402         certReq
.numIssuerNames 
= 0;                             // root for now 
 403         certReq
.issuerNames 
= NULL
; 
 404         certReq
.issuerNameX509 
= NULL
; 
 405         certReq
.certPublicKey 
= subjPubKey
; 
 406         certReq
.issuerPrivateKey 
= signerPrivKey
; 
 407         certReq
.signatureAlg 
= sigAlg
; 
 408         certReq
.signatureOid 
= *sigOid
; 
 409         certReq
.notBefore 
= 0;                                  // TBD - from user 
 410         certReq
.notAfter 
= 60 * 60 * 24 * 30;   // seconds from now 
 411         certReq
.numExtensions 
= numExts
; 
 412         certReq
.extensions 
= exts
; 
 414         reqSet
.NumberOfRequests 
= 1; 
 415         reqSet
.Requests 
= &certReq
; 
 417         /* a CSSM_TP_CALLERAUTH_CONTEXT to specify an OID */ 
 418         memset(&CallerAuthContext
, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT
)); 
 419         memset(&policyId
, 0, sizeof(CSSM_FIELD
)); 
 420         policyId
.FieldOid 
= CSSMOID_APPLE_TP_CSR_GEN
; 
 421         CallerAuthContext
.Policy
.NumberOfPolicyIds 
= 1; 
 422         CallerAuthContext
.Policy
.PolicyIds 
= &policyId
; 
 424         CSSM_RETURN crtn 
= CSSM_TP_SubmitCredRequest(tpHand
, 
 425                 NULL
,                           // PreferredAuthority 
 426                 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE
, 
 432         /* before proceeding, free resources allocated thus far */ 
 433         if(!useAllDefaults
) { 
 434                 freeNameOids(subjectNames
, numNames
); 
 438                 printError("***Error submitting credential request","CSSM_TP_SubmitCredRequest",crtn
); 
 441         crtn 
= CSSM_TP_RetrieveCredResult(tpHand
, 
 443                 NULL
,                           // CallerAuthCredentials 
 448                 printError("***Error retreiving credential request","CSSM_TP_RetrieveCredResult",crtn
); 
 451         if(resultSet 
== NULL
) { 
 452                 printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n"); 
 455         encCert 
= (CSSM_ENCODED_CERT 
*)resultSet
->Results
; 
 456         *csrData 
= encCert
->CertBlob
; 
 458         /* free resources allocated by TP */ 
 459         APP_FREE(refId
.Data
); 
 467 /* this was added in Michael's integration of PR-3420772, but this is an unimplemented command */ 
 470 csr_create(int argc
, char * const *argv
) 
 474         const char *keychainName 
= NULL
; 
 475         CSSM_ALGORITHMS algorithm 
= CSSM_ALGID_RSA
; 
 476         uint32 keySizeInBits 
= 512; 
 478         Boolean always_allow 
= FALSE
; 
 479         CFAbsoluteTime from_time 
= 0.0, to_time 
= 0.0; 
 481         SecAccessRef access 
= NULL
; 
 482         CFMutableArrayRef trusted_list 
= NULL
; 
 483         CFStringRef description 
= NULL
; 
 486     { "create-keypair", key_create_pair, 
 487           "[-a alg] [-s size] [-f date] [-t date] [-d days] [-k keychain] [-u sdux] [-c challenge] description\n" 
 488           " [-k keychain] [-u sewx] description\n" 
 489           "    -a  Look for key with alg as the algorithm, can be rsa, dh, dsa or fee (default rsa)\n" 
 490           "    -s  Look for key with keysize in bits\n" 
 491           "    -c  Add challenge to the key as a challange string\n" 
 492           "    -f  Look for a key at least valid from the specified date\n" 
 493           "    -t  Look for a key at least valid to the specified date\n" 
 494           "    -d  Look for a key at least valid for the number of days specified from now\n" 
 495           "        -u  Look for a key with the specified usage flags (s)igning (d)ecryption (u)nwrapping e(x)change\n" 
 496           "    -k  Look in specified keychain rather than the default search list\n" 
 497           "If no options are provided ask the user interactively", 
 500     while ((ch 
= getopt(argc
, argv
, "a:s:f:t:d:k:AT:h")) != -1) 
 505                         result 
= parse_algorithm(optarg
, &algorithm
); 
 510                         keySizeInBits 
= atoi(optarg
); 
 513                         keychainName 
= optarg
; 
 522                                 trusted_list 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 527                                 SecTrustedApplicationRef app 
= NULL
; 
 528                                 status 
= SecTrustedApplicationCreateFromPath(optarg
, &app
); 
 531                                         sec_error("SecTrustedApplicationCreateFromPath %s: %s", optarg
, sec_errstr(status
)); 
 536                                 CFArrayAppendValue(trusted_list
, app
); 
 542                          result 
= parse_time(optarg
, &from_time
); 
 547                          result 
= parse_time(optarg
, &to_time
); 
 558                         from_time 
= CFAbsoluteTimeGetCurrent(); 
 559                         to_time 
= from_time 
+ days 
* 86400.0; 
 563                         return SHOW_USAGE_MESSAGE
; 
 572                 if (*argv
[0] == '\0') 
 577                 description  
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
); 
 580                 return SHOW_USAGE_MESSAGE
; 
 582                 description 
= CFStringCreateWithCString(NULL
, "<key>", kCFStringEncodingUTF8
); 
 586                 status 
= SecAccessCreate(description
, NULL
, &access
); 
 589                         sec_perror("SecAccessCreate", status
); 
 592                 // @@@ Make the acl always allow now. 
 596                 status 
= SecAccessCreate(description
, trusted_list
, &access
); 
 599                         sec_perror("SecAccessCreate", status
); 
 607         result 
= do_csr_create(keychainName
, access
, algorithm
, keySizeInBits
, from_time
, to_time
); 
 611                 CFRelease(description
); 
 613                 CFRelease(trusted_list
);