| /* Copyright 2014 The ChromiumOS Authors |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| * |
| * Miscellaneous functions for userspace vboot utilities. |
| */ |
| |
| #include <openssl/bn.h> |
| #include <openssl/rsa.h> |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| |
| #include "2common.h" |
| #include "2sha.h" |
| #include "2sysincludes.h" |
| #include "host_common.h" |
| #include "host_key21.h" |
| #include "host_p11.h" |
| #include "openssl_compat.h" |
| #include "util_misc.h" |
| |
| const char *packed_key_sha1_string(const struct vb2_packed_key *key) |
| { |
| uint8_t *buf = ((uint8_t *)key) + key->key_offset; |
| uint32_t buflen = key->key_size; |
| struct vb2_hash hash; |
| static char dest[VB2_SHA1_DIGEST_SIZE * 2 + 1]; |
| |
| vb2_hash_calculate(false, buf, buflen, VB2_HASH_SHA1, &hash); |
| |
| char *dnext = dest; |
| int i; |
| for (i = 0; i < sizeof(hash.sha1); i++) |
| dnext += sprintf(dnext, "%02x", hash.sha1[i]); |
| |
| return dest; |
| } |
| |
| const char *private_key_sha1_string(const struct vb2_private_key *key) |
| { |
| uint8_t *buf; |
| uint32_t buflen; |
| struct vb2_hash hash; |
| static char dest[VB2_SHA1_DIGEST_SIZE * 2 + 1]; |
| |
| if (!key->rsa_private_key || |
| vb_keyb_from_rsa(key->rsa_private_key, &buf, &buflen)) { |
| return "<error>"; |
| } |
| |
| vb2_hash_calculate(false, buf, buflen, VB2_HASH_SHA1, &hash); |
| |
| char *dnext = dest; |
| int i; |
| for (i = 0; i < sizeof(hash.sha1); i++) |
| dnext += sprintf(dnext, "%02x", hash.sha1[i]); |
| |
| free(buf); |
| return dest; |
| } |
| |
| static int vb_keyb_from_modulus(const BIGNUM *rsa_private_key_n, uint32_t modulus_size, |
| uint8_t **keyb_data, uint32_t *keyb_size) |
| { |
| uint32_t i; |
| uint32_t nwords = modulus_size / 4; |
| BIGNUM *N = NULL; |
| BIGNUM *Big1 = NULL, *Big2 = NULL, *Big32 = NULL, *BigMinus1 = NULL; |
| BIGNUM *B = NULL; |
| BIGNUM *N0inv = NULL, *R = NULL, *RR = NULL; |
| BIGNUM *RRTemp = NULL, *NnumBits = NULL; |
| BIGNUM *n = NULL, *rr = NULL; |
| BN_CTX *bn_ctx = BN_CTX_new(); |
| uint32_t n0invout; |
| uint32_t bufsize; |
| uint32_t *outbuf; |
| int retval = 1; |
| |
| bufsize = (2 + nwords + nwords) * sizeof(uint32_t); |
| outbuf = malloc(bufsize); |
| if (!outbuf) |
| goto done; |
| |
| *keyb_data = (uint8_t *)outbuf; |
| *keyb_size = bufsize; |
| |
| *outbuf++ = nwords; |
| |
| /* Initialize BIGNUMs */ |
| #define NEW_BIGNUM(x) do { x = BN_new(); if (!x) goto done; } while (0) |
| NEW_BIGNUM(N); |
| NEW_BIGNUM(Big1); |
| NEW_BIGNUM(Big2); |
| NEW_BIGNUM(Big32); |
| NEW_BIGNUM(BigMinus1); |
| NEW_BIGNUM(N0inv); |
| NEW_BIGNUM(R); |
| NEW_BIGNUM(RR); |
| NEW_BIGNUM(RRTemp); |
| NEW_BIGNUM(NnumBits); |
| NEW_BIGNUM(n); |
| NEW_BIGNUM(rr); |
| NEW_BIGNUM(B); |
| #undef NEW_BIGNUM |
| |
| BN_copy(N, rsa_private_key_n); |
| BN_set_word(Big1, 1L); |
| BN_set_word(Big2, 2L); |
| BN_set_word(Big32, 32L); |
| BN_sub(BigMinus1, Big1, Big2); |
| |
| BN_exp(B, Big2, Big32, bn_ctx); /* B = 2^32 */ |
| |
| /* Calculate and output N0inv = -1 / N[0] mod 2^32 */ |
| BN_mod_inverse(N0inv, N, B, bn_ctx); |
| BN_sub(N0inv, B, N0inv); |
| n0invout = BN_get_word(N0inv); |
| |
| *outbuf++ = n0invout; |
| |
| /* Calculate R = 2^(# of key bits) */ |
| BN_set_word(NnumBits, BN_num_bits(N)); |
| BN_exp(R, Big2, NnumBits, bn_ctx); |
| |
| /* Calculate RR = R^2 mod N */ |
| BN_copy(RR, R); |
| BN_mul(RRTemp, RR, R, bn_ctx); |
| BN_mod(RR, RRTemp, N, bn_ctx); |
| |
| |
| /* Write out modulus as little endian array of integers. */ |
| for (i = 0; i < nwords; ++i) { |
| uint32_t nout; |
| |
| BN_mod(n, N, B, bn_ctx); /* n = N mod B */ |
| nout = BN_get_word(n); |
| *outbuf++ = nout; |
| |
| BN_rshift(N, N, 32); /* N = N/B */ |
| } |
| |
| /* Write R^2 as little endian array of integers. */ |
| for (i = 0; i < nwords; ++i) { |
| uint32_t rrout; |
| |
| BN_mod(rr, RR, B, bn_ctx); /* rr = RR mod B */ |
| rrout = BN_get_word(rr); |
| *outbuf++ = rrout; |
| |
| BN_rshift(RR, RR, 32); /* RR = RR/B */ |
| } |
| |
| outbuf = NULL; |
| retval = 0; |
| |
| done: |
| free(outbuf); |
| /* Free BIGNUMs. */ |
| BN_free(N); |
| BN_free(Big1); |
| BN_free(Big2); |
| BN_free(Big32); |
| BN_free(BigMinus1); |
| BN_free(N0inv); |
| BN_free(R); |
| BN_free(RR); |
| BN_free(RRTemp); |
| BN_free(NnumBits); |
| BN_free(n); |
| BN_free(rr); |
| BN_free(B); |
| |
| BN_CTX_free(bn_ctx); |
| |
| return retval; |
| } |
| |
| static int vb_keyb_from_p11_key(struct pkcs11_key *p11_key, uint8_t **keyb_data, |
| uint32_t *keyb_size) |
| { |
| int ret = 1; |
| uint32_t modulus_size = 0; |
| BIGNUM *N = NULL; |
| uint8_t *modulus = pkcs11_get_modulus(p11_key, &modulus_size); |
| if (!modulus) { |
| fprintf(stderr, "Failed to get modulus from PKCS#11 key\n"); |
| goto done; |
| } |
| |
| N = BN_bin2bn(modulus, modulus_size, NULL); |
| if (!N) { |
| fprintf(stderr, "Failed to call BN_bin2bn()\n"); |
| goto done; |
| } |
| ret = vb_keyb_from_modulus(N, modulus_size, keyb_data, keyb_size); |
| done: |
| BN_free(N); |
| free(modulus); |
| return ret; |
| } |
| |
| int vb_keyb_from_rsa(struct rsa_st *rsa_private_key, uint8_t **keyb_data, uint32_t *keyb_size) |
| { |
| const BIGNUM *N; |
| RSA_get0_key(rsa_private_key, &N, NULL, NULL); |
| if (!N) { |
| fprintf(stderr, "Failed to get N from RSA private key\n"); |
| return 1; |
| } |
| return vb_keyb_from_modulus(N, RSA_size(rsa_private_key), keyb_data, keyb_size); |
| } |
| |
| int vb_keyb_from_private_key(struct vb2_private_key *private_key, uint8_t **keyb_data, |
| uint32_t *keyb_size) |
| { |
| int err; |
| switch (private_key->key_location) { |
| case PRIVATE_KEY_P11: |
| err = vb_keyb_from_p11_key(private_key->p11_key, keyb_data, keyb_size); |
| if (!err) { |
| /* Since ID is not populated in PKCS11, copy the sha into the ID |
| * field. |
| */ |
| struct vb2_hash hash; |
| vb2_hash_calculate(false, *keyb_data, *keyb_size, VB2_HASH_SHA1, &hash); |
| memcpy(private_key->id.raw, hash.sha1, sizeof(private_key->id.raw)); |
| } |
| return err; |
| case PRIVATE_KEY_LOCAL: |
| return vb_keyb_from_rsa(private_key->rsa_private_key, keyb_data, keyb_size); |
| } |
| return 1; |
| } |
| |
| enum vb2_signature_algorithm vb2_get_sig_alg(uint32_t exp, uint32_t bits) |
| { |
| switch (exp) { |
| case RSA_3: |
| switch (bits) { |
| case 2048: |
| return VB2_SIG_RSA2048_EXP3; |
| case 3072: |
| return VB2_SIG_RSA3072_EXP3; |
| } |
| break; |
| case RSA_F4: |
| switch (bits) { |
| case 1024: |
| return VB2_SIG_RSA1024; |
| case 2048: |
| return VB2_SIG_RSA2048; |
| case 4096: |
| return VB2_SIG_RSA4096; |
| case 8192: |
| return VB2_SIG_RSA8192; |
| } |
| } |
| |
| /* no clue */ |
| return VB2_SIG_INVALID; |
| } |