1/* 2 * Examine and test a keychain's identity 3 */ 4#include <Security/Security.h> 5#include <stdlib.h> 6#include <stdio.h> 7#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h> 8#include <security_cdsa_utils/cuPrintCert.h> 9#include <utilLib/common.h> 10#include <utilLib/cspwrap.h> 11#include <clAppUtils/clutils.h> 12 13typedef enum { 14 KC_Nop, 15 KC_GetInfo, 16 KC_LockKC, 17 KC_UnlockKC, 18 KC_SignVfy, 19 KC_KeyCertInfo 20} KcOp; 21 22static void usage(char **argv) 23{ 24 printf("Usage: %s keychain|- cmd [options]\n", argv[0]); 25 printf("Command:\n"); 26 printf(" i get KC info\n"); 27 printf(" k get key and cert info\n"); 28 printf(" l lock\n"); 29 printf(" u unlock\n"); 30 printf(" s sign and verify\n"); 31 printf("Options:\n"); 32 printf(" p=passphrase\n"); 33 printf("Specifying '-' for keychain means NULL, default\n"); 34 exit(1); 35} 36 37static void showError( 38 OSStatus ortn, 39 const char *msg) 40{ 41 const char *errStr = NULL; 42 switch(ortn) { 43 case errSecItemNotFound: 44 errStr = "errSecItemNotFound"; break; 45 case errSecNoSuchKeychain: 46 errStr = "errSecNoSuchKeychain"; break; 47 case errSecNotAvailable: 48 errStr = "errSecNotAvailable"; break; 49 /* more? */ 50 default: 51 if(ortn < (CSSM_BASE_ERROR + 52 (CSSM_ERRORCODE_MODULE_EXTENT * 8))) { 53 /* assume CSSM error */ 54 errStr = cssmErrToStr(ortn); 55 } 56 break; 57 58 } 59 if(errStr) { 60 printf("***Error on %s: %s\n", msg, errStr); 61 } 62 else { 63 printf("***Error on %s: %d(d)\n", msg, (int)ortn); 64 } 65} 66 67static void printDataAsHex( 68 const CSSM_DATA *d, 69 unsigned maxToPrint = 0) // optional, 0 means print it all 70{ 71 unsigned i; 72 bool more = false; 73 uint32 len = d->Length; 74 uint8 *cp = d->Data; 75 76 if((maxToPrint != 0) && (len > maxToPrint)) { 77 len = maxToPrint; 78 more = true; 79 } 80 for(i=0; i<len; i++) { 81 printf("%02X ", ((unsigned char *)cp)[i]); 82 } 83 if(more) { 84 printf("...\n"); 85 } 86 else { 87 printf("\n"); 88 } 89} 90 91static void printKeyHeader( 92 const CSSM_KEYHEADER &hdr) 93{ 94 printf(" Algorithm : "); 95 switch(hdr.AlgorithmId) { 96 case CSSM_ALGID_RSA: 97 printf("RSA\n"); 98 break; 99 case CSSM_ALGID_DSA: 100 printf("DSA\n"); 101 break; 102 case CSSM_ALGID_FEE: 103 printf("FEE\n"); 104 break; 105 case CSSM_ALGID_DH: 106 printf("Diffie-Hellman\n"); 107 break; 108 default: 109 printf("Unknown(%u(d), 0x%x)\n", (unsigned)hdr.AlgorithmId, 110 (unsigned)hdr.AlgorithmId); 111 } 112 printf(" Key Size : %u bits\n", 113 (unsigned)hdr.LogicalKeySizeInBits); 114 printf(" Key Use : "); 115 CSSM_KEYUSE usage = hdr.KeyUsage; 116 if(usage & CSSM_KEYUSE_ANY) { 117 printf("CSSM_KEYUSE_ANY "); 118 } 119 if(usage & CSSM_KEYUSE_ENCRYPT) { 120 printf("CSSM_KEYUSE_ENCRYPT "); 121 } 122 if(usage & CSSM_KEYUSE_DECRYPT) { 123 printf("CSSM_KEYUSE_DECRYPT "); 124 } 125 if(usage & CSSM_KEYUSE_SIGN) { 126 printf("CSSM_KEYUSE_SIGN "); 127 } 128 if(usage & CSSM_KEYUSE_VERIFY) { 129 printf("CSSM_KEYUSE_VERIFY "); 130 } 131 if(usage & CSSM_KEYUSE_SIGN_RECOVER) { 132 printf("CSSM_KEYUSE_SIGN_RECOVER "); 133 } 134 if(usage & CSSM_KEYUSE_VERIFY_RECOVER) { 135 printf("CSSM_KEYUSE_VERIFY_RECOVER "); 136 } 137 if(usage & CSSM_KEYUSE_WRAP) { 138 printf("CSSM_KEYUSE_WRAP "); 139 } 140 if(usage & CSSM_KEYUSE_UNWRAP) { 141 printf("CSSM_KEYUSE_UNWRAP "); 142 } 143 if(usage & CSSM_KEYUSE_DERIVE) { 144 printf("CSSM_KEYUSE_DERIVE "); 145 } 146 printf("\n"); 147 148} 149 150static OSStatus getIdentity( 151 SecKeychainRef kcRef, 152 CSSM_KEYUSE keyUse, 153 SecIdentityRef &idRef) 154{ 155 SecIdentitySearchRef srchRef = nil; 156 OSStatus ortn = SecIdentitySearchCreate(kcRef, keyUse, &srchRef); 157 if(ortn) { 158 showError(ortn, "SecIdentitySearchCreate"); 159 return ortn; 160 } 161 ortn = SecIdentitySearchCopyNext(srchRef, &idRef); 162 if(ortn) { 163 showError(ortn, "SecIdentitySearchCopyNext"); 164 return ortn; 165 } 166 if(CFGetTypeID(idRef) != SecIdentityGetTypeID()) { 167 printf("SecIdentitySearchCopyNext CFTypeID failure!\n"); 168 return paramErr; 169 } 170 return noErr; 171} 172 173static OSStatus getKeyCertInfo( 174 SecCertificateRef certRef, 175 SecKeyRef keyRef, 176 CSSM_KEY_PTR cssmKey, 177 CSSM_CSP_HANDLE cspHand) 178{ 179 /* display the private key */ 180 if(cssmKey == NULL) { 181 printf(" ***malformed CSSM_KEY\n"); 182 } 183 else { 184 printf("Private Key :\n"); 185 printKeyHeader(cssmKey->KeyHeader); 186 printf(" Key Blob : "); 187 printDataAsHex(&cssmKey->KeyData, 8); 188 } 189 190 /* and the cert */ 191 CSSM_DATA certData; 192 OSStatus ortn = SecCertificateGetData(certRef, &certData); 193 if(ortn) { 194 showError(ortn, "SecCertificateGetData"); 195 return ortn; 196 } 197 printf("\nCertificate :\n"); 198 printCert((unsigned char *)certData.Data, (unsigned)certData.Length, 199 CSSM_TRUE); 200 return noErr; 201} 202 203#define SIG_ALG CSSM_ALGID_SHA1WithRSA 204 205static OSStatus signVfy( 206 SecCertificateRef certRef, 207 SecKeyRef keyRef, 208 CSSM_KEY_PTR cssmKey, 209 CSSM_CSP_HANDLE cspHand) 210{ 211 uint8 someData[] = {0,1,2,3,4,5,6,7,8}; 212 CSSM_DATA ptext = {sizeof(someData), someData}; 213 CSSM_DATA sig = {0, NULL}; 214 CSSM_RETURN crtn; 215 216 /* sign with CSPDL */ 217 crtn = cspSign(cspHand, SIG_ALG, cssmKey, &ptext, &sig); 218 if(crtn) { 219 printf("Error signing with private key\n"); 220 return crtn; 221 } 222 223 /* attach to CL */ 224 CSSM_CL_HANDLE clHand = clStartup(); 225 if(clHand == 0) { 226 printf("***Error attaching to CL\n"); 227 return ioErr; 228 } 229 230 /* get the public key from the cert */ 231 CSSM_DATA certData; 232 OSStatus ortn = SecCertificateGetData(certRef, &certData); 233 if(ortn) { 234 showError(ortn, "SecCertificateGetData"); 235 return ortn; 236 } 237 CSSM_KEY_PTR pubKey = NULL; 238 crtn = CSSM_CL_CertGetKeyInfo(clHand, &certData, &pubKey); 239 if(crtn) { 240 printError("CSSM_CL_CertGetKeyInfo", crtn); 241 return crtn; 242 } 243 244 /* attach to raw CSP */ 245 CSSM_CSP_HANDLE rawCspHand = cspStartup(); 246 if(rawCspHand == 0) { 247 printf("***Error attaching to raw CSP\n"); 248 return ioErr; 249 } 250 251 /* verify with raw CSP and raw public key */ 252 crtn = cspSigVerify(rawCspHand, SIG_ALG, pubKey, &ptext, 253 &sig, CSSM_OK); 254 if(crtn) { 255 printf("Error verifying with public key\n"); 256 return crtn; 257 } 258 259 /* free everything */ 260 CSSM_ModuleDetach(rawCspHand); 261 CSSM_ModuleDetach(clHand); 262 printf("...sign with private key, vfy with cert OK\n"); 263 return noErr; 264} 265 266/* get cert and private key (in Sec and CSSM form) from identity */ 267static OSStatus getKeyCert( 268 SecIdentityRef idRef, 269 SecCertificateRef &certRef, // RETURNED 270 SecKeyRef &keyRef, // private key, RETURNED 271 CSSM_KEY_PTR &cssmKey) // private key, RETURNED 272{ 273 OSStatus ortn = SecIdentityCopyCertificate(idRef, &certRef); 274 if(ortn) { 275 showError(ortn, "SecIdentityCopyCertificate"); 276 return ortn; 277 } 278 ortn = SecIdentityCopyPrivateKey(idRef, &keyRef); 279 if(ortn) { 280 showError(ortn, "SecIdentityCopyPrivateKey"); 281 return ortn; 282 } 283 ortn = SecKeyGetCSSMKey(keyRef, (const CSSM_KEY **)&cssmKey); 284 if(ortn) { 285 showError(ortn, "SecKeyGetCSSMKey"); 286 } 287 return ortn; 288} 289 290int main(int argc, char **argv) 291{ 292 SecKeychainRef kcRef = nil; 293 OSStatus ortn; 294 int arg; 295 char *argp; 296 297 /* user-spec'd variables */ 298 KcOp op = KC_Nop; 299 char *pwd = NULL; 300 char *kcName; 301 302 if(argc < 3) { 303 usage(argv); 304 } 305 kcName = argv[1]; 306 if(!strcmp("-", kcName)) { 307 /* null - no open */ 308 kcName = NULL; 309 } 310 switch(argv[2][0]) { 311 case 'i': 312 op = KC_GetInfo; break; 313 case 'l': 314 op = KC_LockKC; break; 315 case 'u': 316 op = KC_UnlockKC; break; 317 case 's': 318 op = KC_SignVfy; break; 319 case 'k': 320 op = KC_KeyCertInfo; break; 321 default: 322 usage(argv); 323 } 324 for(arg=3; arg<argc; arg++) { 325 argp = argv[arg]; 326 switch(argp[0]) { 327 case 'p': 328 pwd = &argp[2]; 329 break; 330 default: 331 usage(argv); 332 } 333 } 334 335 if(kcName != NULL) { 336 ortn = SecKeychainOpen(kcName, &kcRef); 337 if(ortn) { 338 showError(ortn, "SecKeychainOpen"); 339 printf("Cannot open keychain at %s. Aborting.\n", kcName); 340 exit(1); 341 } 342 } 343 344 /* handle trivial commands right now */ 345 switch(op) { 346 case KC_LockKC: 347 ortn = SecKeychainLock(kcRef); 348 if(ortn) { 349 showError(ortn, "SecKeychainLock"); 350 exit(1); 351 } 352 printf("...keychain %s locked.\n", argv[1]); 353 exit(0); 354 355 case KC_UnlockKC: 356 if(pwd == NULL) { 357 printf("***Warning: unlocking with no password\n"); 358 } 359 ortn = SecKeychainUnlock(kcRef, 360 pwd ? strlen(pwd) : 0, 361 pwd, 362 pwd ? true : false); // usePassword 363 if(ortn) { 364 showError(ortn, "SecKeychainUnlock"); 365 exit(1); 366 } 367 printf("...keychain %s unlocked.\n", argv[1]); 368 exit(0); 369 370 case KC_GetInfo: 371 { 372 SecKeychainStatus kcStat; 373 ortn = SecKeychainGetStatus(kcRef, &kcStat); 374 if(ortn) { 375 showError(ortn, "SecKeychainGetStatus"); 376 exit(1); 377 } 378 printf("...SecKeychainStatus = %u ( ", (unsigned)kcStat); 379 if(kcStat & kSecUnlockStateStatus) { 380 printf("UnlockState "); 381 } 382 if(kcStat & kSecReadPermStatus) { 383 printf("RdPerm "); 384 } 385 if(kcStat & kSecWritePermStatus) { 386 printf("WrPerm "); 387 } 388 printf(")\n"); 389 exit(0); 390 } 391 392 default: 393 /* more processing below */ 394 break; 395 } 396 397 /* remaining cmds need an identity */ 398 SecIdentityRef idRef; 399 ortn = getIdentity(kcRef, CSSM_KEYUSE_SIGN, idRef); 400 if(ortn) { 401 printf("***No identity found in keychain %s. Aborting.\n", kcName); 402 exit(1); 403 } 404 405 /* and a CSP */ 406 CSSM_CSP_HANDLE cspHand; 407 ortn = SecKeychainGetCSPHandle(kcRef, &cspHand); 408 if(ortn) { 409 showError(ortn, "SecKeychainGetCSPHandle"); 410 exit(1); 411 } 412 413 /* and the cert and keys */ 414 SecCertificateRef certRef = nil; 415 SecKeyRef keyRef = nil; 416 CSSM_KEY_PTR privKey = NULL; 417 ortn = getKeyCert(idRef, certRef, keyRef, privKey); 418 if(ortn) { 419 printf("***Incomplete identity\n"); 420 exit(1); 421 } 422 423 switch(op) { 424 case KC_KeyCertInfo: 425 ortn = getKeyCertInfo(certRef, keyRef, privKey, cspHand); 426 break; 427 case KC_SignVfy: 428 ortn = signVfy(certRef, keyRef, privKey, cspHand); 429 break; 430 default: 431 printf("BRRRZAP!\n"); 432 exit(1); 433 } 434 CFRelease(idRef); 435 if(kcRef) { 436 CFRelease(kcRef); 437 } 438 return (int)ortn; 439} 440