/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Implementation of RSA utility functions. */ #include "sysincludes.h" #include "cryptolib.h" #include "stateful_util.h" #include "utility.h" #include "vboot_api.h" uint64_t RSAProcessedKeySize(uint64_t algorithm, uint64_t* out_size) { int key_len; /* Key length in bytes. (int type matches siglen_map) */ if (algorithm < kNumAlgorithms) { key_len = siglen_map[algorithm]; /* Total size needed by a RSAPublicKey buffer is = * 2 * key_len bytes for the n and rr arrays * + sizeof len + sizeof n0inv. */ *out_size = (2 * key_len + sizeof(uint32_t) + sizeof(uint32_t)); return 1; } return 0; } RSAPublicKey* RSAPublicKeyNew(void) { RSAPublicKey* key = (RSAPublicKey*) VbExMalloc(sizeof(RSAPublicKey)); key->n = NULL; key->rr = NULL; key->len = 0; key->algorithm = kNumAlgorithms; return key; } void RSAPublicKeyFree(RSAPublicKey* key) { if (key) { if (key->n) VbExFree(key->n); if (key->rr) VbExFree(key->rr); VbExFree(key); } } RSAPublicKey* RSAPublicKeyFromBuf(const uint8_t* buf, uint64_t len) { RSAPublicKey* key = RSAPublicKeyNew(); MemcpyState st; uint64_t key_len; StatefulInit(&st, (void*)buf, len); StatefulMemcpy(&st, &key->len, sizeof(key->len)); /* key length in bytes (avoiding possible 32-bit rollover) */ key_len = key->len; key_len *= sizeof(uint32_t); /* Sanity Check the key length. */ if (RSA1024NUMBYTES != key_len && RSA2048NUMBYTES != key_len && RSA4096NUMBYTES != key_len && RSA8192NUMBYTES != key_len) { RSAPublicKeyFree(key); return NULL; } key->n = (uint32_t*) VbExMalloc(key_len); key->rr = (uint32_t*) VbExMalloc(key_len); StatefulMemcpy(&st, &key->n0inv, sizeof(key->n0inv)); StatefulMemcpy(&st, key->n, key_len); StatefulMemcpy(&st, key->rr, key_len); if (st.overrun || st.remaining_len != 0) { /* Underrun or overrun. */ RSAPublicKeyFree(key); return NULL; } return key; } int RSAVerifyBinary_f(const uint8_t* key_blob, const RSAPublicKey* key, const uint8_t* buf, uint64_t len, const uint8_t* sig, unsigned int algorithm) { RSAPublicKey* verification_key = NULL; uint8_t* digest = NULL; uint64_t key_size; int sig_size; int success; if (algorithm >= (unsigned int)kNumAlgorithms) return 0; /* Invalid algorithm. */ if (!RSAProcessedKeySize(algorithm, &key_size)) return 0; sig_size = siglen_map[algorithm]; if (key_blob && !key) verification_key = RSAPublicKeyFromBuf(key_blob, key_size); else if (!key_blob && key) verification_key = (RSAPublicKey*) key; /* Supress const warning. */ else return 0; /* Both can't be NULL or non-NULL. */ /* Ensure we have a valid key. */ if (!verification_key) return 0; digest = DigestBuf(buf, len, algorithm); success = RSAVerify(verification_key, sig, (uint32_t)sig_size, (uint8_t)algorithm, digest); VbExFree(digest); if (!key) RSAPublicKeyFree(verification_key); /* Only free if we allocated it. */ return success; } /* Version of RSAVerifyBinary_f() where instead of the raw binary blob * of data, its digest is passed as the argument. */ int RSAVerifyBinaryWithDigest_f(const uint8_t* key_blob, const RSAPublicKey* key, const uint8_t* digest, const uint8_t* sig, unsigned int algorithm) { RSAPublicKey* verification_key = NULL; uint64_t key_size; int sig_size; int success; if (algorithm >= (unsigned int)kNumAlgorithms) return 0; /* Invalid algorithm. */ if (!RSAProcessedKeySize(algorithm, &key_size)) return 0; sig_size = siglen_map[algorithm]; if (key_blob && !key) verification_key = RSAPublicKeyFromBuf(key_blob, key_size); else if (!key_blob && key) verification_key = (RSAPublicKey*) key; /* Supress const warning. */ else return 0; /* Both can't be NULL or non-NULL. */ /* Ensure we have a valid key. */ if (!verification_key) return 0; success = RSAVerify(verification_key, sig, (uint32_t)sig_size, (uint8_t)algorithm, digest); if (!key) RSAPublicKeyFree(verification_key); /* Only free if we allocated it. */ return success; }