1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <limits.h> 30 #include <sys/types.h> 31 #include <sys/stat.h> 32 #include <fcntl.h> 33 #include <unistd.h> 34 #include <dirent.h> 35 #include <strings.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <errno.h> 39 #include <sys/mman.h> 40 #include <md5.h> 41 #include <pthread.h> 42 43 #include <cryptoutil.h> 44 45 #include <kmfapi.h> 46 #include <sys/crypto/elfsign.h> 47 #include <libelfsign.h> 48 49 #include <synch.h> 50 51 const char _PATH_ELFSIGN_CRYPTO_CERTS[] = CRYPTO_CERTS_DIR; 52 const char _PATH_ELFSIGN_ETC_CERTS[] = ETC_CERTS_DIR; 53 54 /* 55 * The CACERT and OBJCACERT are the Cryptographic Trust Anchors 56 * for the Solaris Cryptographic Framework. 57 */ 58 static const char _PATH_CRYPTO_CACERT[] = CRYPTO_CERTS_DIR "/CA"; 59 static const char _PATH_CRYPTO_OBJCACERT[] = CRYPTO_CERTS_DIR "/SUNWObjectCA"; 60 static ELFCert_t CACERT = NULL; 61 static ELFCert_t OBJCACERT = NULL; 62 static pthread_mutex_t ca_mutex = PTHREAD_MUTEX_INITIALIZER; 63 64 static void elfcertlib_freecert(ELFsign_t, ELFCert_t); 65 static ELFCert_t elfcertlib_allocatecert(void); 66 67 /* 68 * elfcertlib_verifycert - Verify the Cert with a Trust Anchor 69 * 70 * IN ess - elfsign context structure 71 * cert 72 * OUT NONE 73 * RETURN TRUE/FALSE 74 * 75 * We first setup the Trust Anchor (CA and SUNWObjectCA) certs 76 * if it hasn't been done already. We verify that the files on disk 77 * are those we expected. 78 * 79 * We then verify the given cert using the publickey of a TA. 80 * If the passed in cert is a TA or it has been verified already we 81 * short cut and return TRUE without futher validation. 82 */ 83 /*ARGSUSED*/ 84 boolean_t 85 elfcertlib_verifycert(ELFsign_t ess, ELFCert_t cert) 86 { 87 KMF_RETURN rv; 88 if ((cert->c_verified == E_OK) || (cert->c_verified == E_IS_TA)) { 89 return (B_TRUE); 90 } 91 92 (void) pthread_mutex_lock(&ca_mutex); 93 if (CACERT == NULL) { 94 (void) elfcertlib_getcert(ess, (char *)_PATH_CRYPTO_CACERT, 95 NULL, &CACERT, ES_GET); 96 } 97 if (OBJCACERT == NULL) { 98 (void) elfcertlib_getcert(ess, (char *)_PATH_CRYPTO_OBJCACERT, 99 NULL, &OBJCACERT, ES_GET); 100 } 101 (void) pthread_mutex_unlock(&ca_mutex); 102 103 if (CACERT != NULL) { 104 rv = KMF_VerifyCertWithCert(ess->es_kmfhandle, 105 (const KMF_DATA *)&cert->c_cert, 106 (const KMF_DATA *)&CACERT->c_cert.certificate); 107 if (rv == KMF_OK) { 108 if (ess->es_certCAcallback != NULL) 109 (ess->es_certvercallback)(ess->es_callbackctx, 110 cert, CACERT); 111 cert->c_verified = E_OK; 112 return (B_TRUE); 113 } 114 } 115 116 if (OBJCACERT != NULL) { 117 rv = KMF_VerifyCertWithCert(ess->es_kmfhandle, 118 (const KMF_DATA *)&cert->c_cert, 119 (const KMF_DATA *)&OBJCACERT->c_cert.certificate); 120 if (rv == KMF_OK) { 121 if (ess->es_certCAcallback != NULL) 122 (ess->es_certvercallback)(ess->es_callbackctx, 123 cert, OBJCACERT); 124 cert->c_verified = E_OK; 125 return (B_TRUE); 126 } 127 } 128 129 return (B_FALSE); 130 } 131 132 /* 133 * elfcertlib_getcert - Get the certificate for signer_DN 134 * 135 * IN ess - elfsign context structure 136 * cert_pathname - path to cert (May be NULL) 137 * signer_DN - The DN we are looking for (May be NULL) 138 * action - indicates crypto verification call 139 * OUT certp - allocated/loaded ELFCert_t 140 * 141 * If the cert_pathname is passed use it and don't search. 142 * Otherwise, go looking in certificate directories 143 */ 144 boolean_t 145 elfcertlib_getcert(ELFsign_t ess, char *cert_pathname, 146 char *signer_DN, ELFCert_t *certp, enum ES_ACTION action) 147 { 148 KMF_RETURN rv; 149 ELFCert_t cert = NULL; 150 KMF_FINDCERT_PARAMS fcparams; 151 KMF_X509_DER_CERT certbuf[2]; 152 uint32_t ncerts; 153 boolean_t ret = B_FALSE; 154 char *pathlist[3], **plp; 155 156 cryptodebug("elfcertlib_getcert: path=%s, DN=%s", 157 cert_pathname ? cert_pathname : "-none-", 158 signer_DN ? signer_DN : "-none-"); 159 *certp = NULL; 160 if (cert_pathname == NULL && signer_DN == NULL) { 161 cryptodebug("elfcertlib_getcert: lack of specificity"); 162 return (ret); 163 } 164 165 plp = pathlist; 166 if (cert_pathname != NULL) { 167 /* look in the specified object */ 168 *plp++ = cert_pathname; 169 } else { 170 /* look in the certificate directories */ 171 *plp++ = (char *)_PATH_ELFSIGN_CRYPTO_CERTS; 172 /* 173 * crypto verifications don't search beyond 174 * _PATH_ELFSIGN_CRYPTO_CERTS 175 */ 176 if (action != ES_GET_CRYPTO) 177 *plp++ = (char *)_PATH_ELFSIGN_ETC_CERTS; 178 } 179 *plp = NULL; 180 181 if ((cert = elfcertlib_allocatecert()) == NULL) { 182 return (ret); 183 } 184 185 for (plp = pathlist; *plp; plp++) { 186 (void) memset(&fcparams, 0, sizeof (fcparams)); 187 fcparams.kstype = KMF_KEYSTORE_OPENSSL; 188 fcparams.sslparms.certfile = *plp; 189 fcparams.subject = signer_DN; 190 ncerts = 2; 191 192 rv = KMF_FindCert(ess->es_kmfhandle, &fcparams, certbuf, 193 &ncerts); 194 if (rv != KMF_OK) 195 continue; 196 if (ncerts > 1 && signer_DN == NULL) { 197 /* There can be only one */ 198 cryptodebug("elfcertlib_getcert: " 199 "too many certificates found in %s", 200 cert_pathname); 201 goto cleanup; 202 } 203 /* found it, cache subject and issuer */ 204 cert->c_cert = certbuf[0]; 205 rv = KMF_GetCertSubjectNameString(ess->es_kmfhandle, 206 &cert->c_cert.certificate, &cert->c_subject); 207 if (rv != KMF_OK) 208 goto cleanup; 209 210 rv = KMF_GetCertIssuerNameString(ess->es_kmfhandle, 211 &cert->c_cert.certificate, &cert->c_issuer); 212 if (rv != KMF_OK) 213 goto cleanup; 214 break; 215 } 216 if (*plp == NULL) { 217 cryptodebug("elfcertlib_getcert: no certificate found"); 218 goto cleanup; 219 } 220 221 cert->c_verified = E_UNCHECKED; 222 223 /* 224 * If the cert we are loading it the trust anchor (ie the CA) then 225 * we mark it as such in cert. This is so that we don't attempt 226 * to verify it later. The CA is always implicitly verified. 227 */ 228 if (cert_pathname != NULL && ( 229 strcmp(cert_pathname, _PATH_CRYPTO_CACERT) == 0 || 230 strcmp(cert_pathname, _PATH_CRYPTO_OBJCACERT) == 0)) { 231 if (ess->es_certCAcallback != NULL) 232 (ess->es_certCAcallback)(ess->es_callbackctx, cert, 233 cert_pathname); 234 cert->c_verified = E_IS_TA; 235 } 236 237 ret = B_TRUE; 238 239 cleanup: 240 if (ret) { 241 *certp = cert; 242 } else { 243 if (cert != NULL) 244 elfcertlib_freecert(ess, cert); 245 if (signer_DN != NULL) 246 cryptoerror(LOG_ERR, "unable to find a certificate " 247 "for DN: %s", signer_DN); 248 else 249 cryptoerror(LOG_ERR, "unable to load certificate " 250 "from %s", cert_pathname); 251 } 252 return (ret); 253 } 254 255 /* 256 * elfcertlib_loadprivatekey - Load the private key from path 257 * 258 * IN ess - elfsign context structure 259 * cert 260 * pathname 261 * OUT cert 262 * RETURNS TRUE/FALSE 263 */ 264 boolean_t 265 elfcertlib_loadprivatekey(ELFsign_t ess, ELFCert_t cert, const char *pathname) 266 { 267 KMF_RETURN rv = KMF_OK; 268 uint32_t nkeys = 2; 269 KMF_FINDKEY_PARAMS fkparams; 270 KMF_KEY_HANDLE keybuf[2]; 271 272 (void) memset(&fkparams, 0, sizeof (fkparams)); 273 fkparams.keyclass = KMF_ASYM_PRI; 274 fkparams.kstype = KMF_KEYSTORE_OPENSSL; 275 fkparams.sslparms.keyfile = (char *)pathname; 276 277 rv = KMF_FindKey(ess->es_kmfhandle, &fkparams, keybuf, &nkeys); 278 if (rv != KMF_OK) 279 return (B_FALSE); 280 if (nkeys != 1) { 281 /* lack of specificity */ 282 cryptodebug("found %d keys at %s", nkeys, pathname); 283 return (B_FALSE); 284 } 285 cert->c_privatekey = keybuf[0]; 286 cryptodebug("key %s loaded", pathname); 287 return (B_TRUE); 288 } 289 290 /* 291 * elfcertlib_loadtokenkey - Load the private key from token 292 * 293 * IN ess - elfsign context structure 294 * cert 295 * token_label 296 * pin 297 * OUT cert 298 * RETURNS TRUE/FALSE 299 */ 300 boolean_t 301 elfcertlib_loadtokenkey(ELFsign_t ess, ELFCert_t cert, 302 const char *token_label, const char *pin) 303 { 304 KMF_RETURN rv = KMF_OK; 305 KMF_FINDKEY_PARAMS fkparams; 306 KMF_CONFIG_PARAMS cfgparams; 307 uint32_t nkeys = 1; 308 char *idstr = NULL; 309 char *err = NULL; 310 311 (void) memset(&fkparams, 0, sizeof (fkparams)); 312 (void) memset(&cfgparams, 0, sizeof (cfgparams)); 313 314 cfgparams.kstype = KMF_KEYSTORE_PK11TOKEN; 315 cfgparams.pkcs11config.label = (char *)token_label; 316 cfgparams.pkcs11config.readonly = B_TRUE; 317 rv = KMF_ConfigureKeystore(ess->es_kmfhandle, &cfgparams); 318 if (rv != KMF_OK) { 319 if (KMF_GetKMFErrorString(rv, &err) == KMF_OK) { 320 cryptodebug("Error configuring token access:" 321 " %s\n", err); 322 free(err); 323 } 324 return (B_FALSE); 325 } 326 327 fkparams.idstr = idstr; 328 fkparams.kstype = KMF_KEYSTORE_PK11TOKEN; 329 fkparams.keyclass = KMF_ASYM_PRI; 330 fkparams.cred.cred = (char *)pin; 331 fkparams.cred.credlen = (pin != NULL ? strlen(pin) : 0); 332 fkparams.pkcs11parms.private = B_TRUE; 333 334 /* 335 * We will search for the key based on the ID attribute 336 * which was added when the key was created. ID is 337 * a SHA-1 hash of the public modulus shared by the 338 * key and the certificate. 339 */ 340 rv = KMF_GetCertIDString(&cert->c_cert.certificate, &idstr); 341 if (rv != KMF_OK) { 342 if (KMF_GetKMFErrorString(rv, &err) == KMF_OK) { 343 cryptodebug("Error getting ID from cert: %s\n", err); 344 free(err); 345 } 346 return (B_FALSE); 347 } 348 fkparams.idstr = idstr; 349 350 rv = KMF_FindKey(ess->es_kmfhandle, &fkparams, 351 &cert->c_privatekey, &nkeys); 352 if (rv != KMF_OK || nkeys != 1) { 353 if (KMF_GetKMFErrorString(rv, &err) == KMF_OK) { 354 cryptodebug("Error finding private key: %s\n", err); 355 free(err); 356 } 357 free(idstr); 358 return (B_FALSE); 359 } 360 cryptodebug("key found in %s", token_label); 361 cryptodebug("elfcertlib_loadprivatekey = 0x%.8X", 362 &cert->c_privatekey); 363 364 free(idstr); 365 return (B_TRUE); 366 } 367 368 static const CK_BYTE MD5_DER_PREFIX[] = {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 369 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10}; 370 371 /* 372 * elfcertlib_sign - sign the given DATA using the privatekey in cert 373 * 374 * IN ess - elfsign context structure 375 * cert 376 * data 377 * data_len 378 * OUT sig - must be big enough to hold the signature of data 379 * Caller must allocate 380 * sig_len - actual length used; 0 on failure. 381 * RETURNS TRUE/FALSE 382 */ 383 /*ARGSUSED*/ 384 boolean_t 385 elfcertlib_sign(ELFsign_t ess, ELFCert_t cert, 386 const uchar_t *data, size_t data_len, 387 uchar_t *sig, size_t *sig_len) 388 { 389 KMF_RETURN ret = KMF_OK; 390 KMF_DATA tobesigned; 391 KMF_DATA signature; 392 uchar_t der_data[sizeof (MD5_DER_PREFIX) + MD5_DIGEST_LENGTH]; 393 394 if (ess->es_version <= FILESIG_VERSION2) { 395 /* compatibility: take MD5 hash of SHA1 hash */ 396 size_t derlen = MD5_DIGEST_LENGTH; 397 MD5_CTX ctx; 398 399 /* 400 * first: digest using software-based methods, don't 401 * rely on the token for hashing. 402 */ 403 MD5Init(&ctx); 404 MD5Update(&ctx, data, data_len); 405 MD5Final(&der_data[sizeof (MD5_DER_PREFIX)], &ctx); 406 407 /* 408 * second: insert prefix 409 */ 410 (void) memcpy(der_data, MD5_DER_PREFIX, 411 sizeof (MD5_DER_PREFIX)); 412 /* 413 * prepare to sign the local buffer 414 */ 415 tobesigned.Data = (uchar_t *)der_data; 416 tobesigned.Length = sizeof (MD5_DER_PREFIX) + derlen; 417 } else { 418 tobesigned.Data = (uchar_t *)data; 419 tobesigned.Length = data_len; 420 } 421 422 signature.Data = (uchar_t *)sig; 423 signature.Length = *sig_len; 424 425 ret = KMF_SignDataWithKey(ess->es_kmfhandle, 426 &cert->c_privatekey, (KMF_OID *)&KMFOID_RSA, 427 &tobesigned, &signature); 428 429 if (ret != KMF_OK) { 430 char *err; 431 if (KMF_GetKMFErrorString(ret, &err) == KMF_OK && 432 err != NULL) { 433 cryptodebug("Error signing data: %s\n", err); 434 free(err); 435 } 436 *sig_len = 0; 437 return (B_FALSE); 438 } 439 *sig_len = signature.Length; 440 return (B_TRUE); 441 } 442 443 /* 444 * elfcertlib_verifysig - verify the given DATA using the public key in cert 445 * 446 * IN ess - elfsign context structure 447 * cert 448 * signature 449 * sig_len 450 * data 451 * data_len 452 * OUT N/A 453 * RETURNS TRUE/FALSE 454 */ 455 boolean_t 456 elfcertlib_verifysig(ELFsign_t ess, ELFCert_t cert, 457 const uchar_t *signature, size_t sig_len, 458 const uchar_t *data, size_t data_len) 459 { 460 KMF_RETURN rv; 461 KMF_DATA indata; 462 KMF_DATA insig; 463 KMF_ALGORITHM_INDEX algid; 464 465 indata.Data = (uchar_t *)data; 466 indata.Length = data_len; 467 insig.Data = (uchar_t *)signature; 468 insig.Length = sig_len; 469 470 if (ess->es_version <= FILESIG_VERSION2) 471 algid = KMF_ALGID_MD5WithRSA; 472 else 473 algid = KMF_ALGID_RSA; 474 475 /* 476 * We tell KMF to use the OpenSSL verification 477 * APIs here to avoid a circular dependency with 478 * kcfd and libpkcs11. 479 */ 480 rv = KMF_VerifyDataWithCert(ess->es_kmfhandle, 481 KMF_KEYSTORE_OPENSSL, algid, 482 &indata, &insig, &cert->c_cert.certificate); 483 484 return ((rv == KMF_OK)); 485 } 486 487 /* 488 * elfcertlib_getdn 489 * 490 * IN cert 491 * OUT NONE 492 * RETURN dn or NULL 493 */ 494 char * 495 elfcertlib_getdn(ELFCert_t cert) 496 { 497 cryptodebug("elfcertlib_getdn"); 498 499 return (cert->c_subject); 500 } 501 502 /* 503 * elfcertlib_getissuer 504 * 505 * IN cert 506 * OUT NONE 507 * RETURN dn or NULL 508 */ 509 char * 510 elfcertlib_getissuer(ELFCert_t cert) 511 { 512 cryptodebug("elfcertlib_issuer"); 513 514 return (cert->c_issuer); 515 } 516 517 boolean_t 518 elfcertlib_init(ELFsign_t ess) 519 { 520 boolean_t rc = B_TRUE; 521 KMF_RETURN rv; 522 if (ess->es_kmfhandle == NULL) { 523 rv = KMF_Initialize(&ess->es_kmfhandle, NULL, NULL); 524 if (rv != KMF_OK) { 525 cryptoerror(LOG_ERR, 526 "unable to initialize KMF library"); 527 rc = B_FALSE; 528 } 529 } 530 return (rc); 531 } 532 533 void 534 elfcertlib_fini(ELFsign_t ess) 535 { 536 (void) KMF_Finalize(ess->es_kmfhandle); 537 } 538 539 /* 540 * set the token device 541 */ 542 boolean_t 543 elfcertlib_settoken(ELFsign_t ess, char *token) 544 { 545 boolean_t rc = B_TRUE; 546 KMF_RETURN rv; 547 KMF_CONFIG_PARAMS cfgparams; 548 549 (void) memset(&cfgparams, 0, sizeof (cfgparams)); 550 cfgparams.kstype = KMF_KEYSTORE_PK11TOKEN; 551 cfgparams.pkcs11config.label = token; 552 cfgparams.pkcs11config.readonly = B_TRUE; 553 rv = KMF_ConfigureKeystore(ess->es_kmfhandle, &cfgparams); 554 if (rv != KMF_OK) { 555 cryptoerror(LOG_ERR, "unable to select token\n"); 556 rc = B_FALSE; 557 } 558 559 return (rc); 560 } 561 562 /* 563 * set the certificate CA identification callback 564 */ 565 void 566 elfcertlib_setcertCAcallback(ELFsign_t ess, 567 void (*cb)(void *, ELFCert_t, char *)) 568 { 569 ess->es_certCAcallback = cb; 570 } 571 572 /* 573 * set the certificate verification callback 574 */ 575 void 576 elfcertlib_setcertvercallback(ELFsign_t ess, 577 void (*cb)(void *, ELFCert_t, ELFCert_t)) 578 { 579 ess->es_certvercallback = cb; 580 } 581 582 583 /* 584 * elfcertlib_releasecert - release a cert 585 * 586 * IN cert 587 * OUT cert 588 * RETURN N/A 589 * 590 */ 591 void 592 elfcertlib_releasecert(ELFsign_t ess, ELFCert_t cert) 593 { 594 elfcertlib_freecert(ess, cert); 595 } 596 597 /* 598 * elfcertlib_allocatecert - create a new ELFCert_t 599 * 600 * IN N/A 601 * OUT N/A 602 * RETURN ELFCert_t, NULL on failure. 603 */ 604 static ELFCert_t 605 elfcertlib_allocatecert(void) 606 { 607 ELFCert_t cert = NULL; 608 609 cert = malloc(sizeof (struct ELFCert_s)); 610 if (cert == NULL) { 611 cryptoerror(LOG_ERR, 612 "elfcertlib_allocatecert: malloc failed %s", 613 strerror(errno)); 614 return (NULL); 615 } 616 (void) memset(cert, 0, sizeof (struct ELFCert_s)); 617 cert->c_verified = E_UNCHECKED; 618 cert->c_subject = NULL; 619 cert->c_issuer = NULL; 620 return (cert); 621 } 622 623 /* 624 * elfcertlib_freecert - freeup the memory of a cert 625 * 626 * IN cert 627 * OUT cert 628 * RETURN N/A 629 * 630 */ 631 static void 632 elfcertlib_freecert(ELFsign_t ess, ELFCert_t cert) 633 { 634 if (cert == NULL) 635 return; 636 637 free(cert->c_subject); 638 free(cert->c_issuer); 639 640 KMF_FreeKMFCert(ess->es_kmfhandle, &cert->c_cert); 641 KMF_FreeKMFKey(ess->es_kmfhandle, &cert->c_privatekey); 642 643 free(cert); 644 } 645