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