1322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 2322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah * Use of this source code is governed by a BSD-style license that can be 3322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah * found in the LICENSE file. 4322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah */ 5322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 6322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah/* C port of DumpPublicKey.java from the Android Open source project with 7322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah * support for additional RSA key sizes. (platform/system/core,git/libmincrypt 8322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah * /tools/DumpPublicKey.java). Uses the OpenSSL X509 and BIGNUM library. 9322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah */ 10322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 11322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah#include <openssl/pem.h> 124e4c19602edf3834b50d66d3ba067e895aca6fa0Bill Richardson 134e4c19602edf3834b50d66d3ba067e895aca6fa0Bill Richardson#include <stdint.h> 14322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah#include <string.h> 15322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah#include <unistd.h> 16322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 17322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah/* Command line tool to extract RSA public keys from X.509 certificates 18322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah * and output a pre-processed version of keys for use by RSA verification 19322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah * routines. 20322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah */ 21322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 22322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shahint check(RSA* key) { 23322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah int public_exponent = BN_get_word(key->e); 24322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah int modulus = BN_num_bits(key->n); 25322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 26322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah if (public_exponent != 65537) { 27322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah fprintf(stderr, "WARNING: Public exponent should be 65537 (but is %d).\n", 28322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah public_exponent); 29322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah } 30322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 31322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah if (modulus != 1024 && modulus != 2048 && modulus != 4096 32322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah && modulus != 8192) { 33322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah fprintf(stderr, "ERROR: Unknown modulus length = %d.\n", modulus); 34322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah return 0; 35322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah } 36322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah return 1; 37322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah} 38322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 39322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah/* Pre-processes and outputs RSA public key to standard out. 40322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah */ 41322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shahvoid output(RSA* key) { 42322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah int i, nwords; 43322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BIGNUM *N = key->n; 4448ed9b87eb1a8d09523778ee5005111bc0662a34Gaurav Shah BIGNUM *Big1 = NULL, *Big2 = NULL, *Big32 = NULL, *BigMinus1 = NULL; 4548ed9b87eb1a8d09523778ee5005111bc0662a34Gaurav Shah BIGNUM *B = NULL; 4648ed9b87eb1a8d09523778ee5005111bc0662a34Gaurav Shah BIGNUM *N0inv= NULL, *R = NULL, *RR = NULL, *RRTemp = NULL, *NnumBits = NULL; 4748ed9b87eb1a8d09523778ee5005111bc0662a34Gaurav Shah BIGNUM *n = NULL, *rr = NULL; 48322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_CTX *bn_ctx = BN_CTX_new(); 49322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah uint32_t n0invout; 50322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 51322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah N = key->n; 52322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah /* Output size of RSA key in 32-bit words */ 53322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah nwords = BN_num_bits(N) / 32; 5416ca324d4373a754a2314ad79c075a61c2b5ea9aGaurav Shah if (-1 == write(1, &nwords, sizeof(nwords))) 5516ca324d4373a754a2314ad79c075a61c2b5ea9aGaurav Shah goto failure; 5616ca324d4373a754a2314ad79c075a61c2b5ea9aGaurav Shah 57322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 58322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah /* Initialize BIGNUMs */ 59322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah Big1 = BN_new(); 60322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah Big2 = BN_new(); 61322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah Big32 = BN_new(); 62322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BigMinus1 = BN_new(); 63322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah N0inv= BN_new(); 64322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah R = BN_new(); 65322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah RR = BN_new(); 66322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah RRTemp = BN_new(); 67322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah NnumBits = BN_new(); 68322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah n = BN_new(); 69322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah rr = BN_new(); 70322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 71322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 72322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_set_word(Big1, 1L); 73322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_set_word(Big2, 2L); 74322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_set_word(Big32, 32L); 75322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_sub(BigMinus1, Big1, Big2); 76322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 77322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah B = BN_new(); 78322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_exp(B, Big2, Big32, bn_ctx); /* B = 2^32 */ 79322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 80322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah /* Calculate and output N0inv = -1 / N[0] mod 2^32 */ 81322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_mod_inverse(N0inv, N, B, bn_ctx); 82322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_sub(N0inv, B, N0inv); 83322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah n0invout = BN_get_word(N0inv); 8416ca324d4373a754a2314ad79c075a61c2b5ea9aGaurav Shah if (-1 == write(1, &n0invout, sizeof(n0invout))) 8516ca324d4373a754a2314ad79c075a61c2b5ea9aGaurav Shah goto failure; 86322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 87322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah /* Calculate R = 2^(# of key bits) */ 88322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_set_word(NnumBits, BN_num_bits(N)); 89322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_exp(R, Big2, NnumBits, bn_ctx); 90322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 91322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah /* Calculate RR = R^2 mod N */ 92322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_copy(RR, R); 93322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_mul(RRTemp, RR, R, bn_ctx); 94322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_mod(RR, RRTemp, N, bn_ctx); 95322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 96322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 97322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah /* Write out modulus as little endian array of integers. */ 98322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah for (i = 0; i < nwords; ++i) { 99322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah uint32_t nout; 100322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 101322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_mod(n, N, B, bn_ctx); /* n = N mod B */ 102322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah nout = BN_get_word(n); 10316ca324d4373a754a2314ad79c075a61c2b5ea9aGaurav Shah if (-1 == write(1, &nout, sizeof(nout))) 10416ca324d4373a754a2314ad79c075a61c2b5ea9aGaurav Shah goto failure; 105322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 106322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_rshift(N, N, 32); /* N = N/B */ 107322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah } 108322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 109322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah /* Write R^2 as little endian array of integers. */ 110322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah for (i = 0; i < nwords; ++i) { 111322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah uint32_t rrout; 112322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 113322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_mod(rr, RR, B, bn_ctx); /* rr = RR mod B */ 114322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah rrout = BN_get_word(rr); 11516ca324d4373a754a2314ad79c075a61c2b5ea9aGaurav Shah if (-1 == write(1, &rrout, sizeof(rrout))) 11616ca324d4373a754a2314ad79c075a61c2b5ea9aGaurav Shah goto failure; 117322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 118322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_rshift(RR, RR, 32); /* RR = RR/B */ 119322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah } 120322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 12116ca324d4373a754a2314ad79c075a61c2b5ea9aGaurav Shahfailure: 122322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah /* Free BIGNUMs. */ 123322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_free(Big1); 124322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_free(Big2); 125322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_free(Big32); 126322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_free(BigMinus1); 127322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_free(N0inv); 128322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_free(R); 129322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_free(RRTemp); 130322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_free(NnumBits); 131322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_free(n); 132322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah BN_free(rr); 133322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 134322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah} 135322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 136322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shahint main(int argc, char* argv[]) { 137551037b10e427687b7115751c7d613d66459c427Gaurav Shah int cert_mode = 0; 138322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah FILE* fp; 139322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah X509* cert = NULL; 140322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah RSA* pubkey = NULL; 141322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah EVP_PKEY* key; 142feb2518166b1cd181e607c611cbb610f0c7300daBill Richardson char *progname; 143322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 144551037b10e427687b7115751c7d613d66459c427Gaurav Shah if (argc != 3 || (strcmp(argv[1], "-cert") && strcmp(argv[1], "-pub"))) { 145feb2518166b1cd181e607c611cbb610f0c7300daBill Richardson progname = strrchr(argv[0], '/'); 146feb2518166b1cd181e607c611cbb610f0c7300daBill Richardson if (progname) 147feb2518166b1cd181e607c611cbb610f0c7300daBill Richardson progname++; 148feb2518166b1cd181e607c611cbb610f0c7300daBill Richardson else 149feb2518166b1cd181e607c611cbb610f0c7300daBill Richardson progname = argv[0]; 150feb2518166b1cd181e607c611cbb610f0c7300daBill Richardson fprintf(stderr, "Usage: %s <-cert | -pub> <file>\n", progname); 151322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah return -1; 152322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah } 153322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 154551037b10e427687b7115751c7d613d66459c427Gaurav Shah if (!strcmp(argv[1], "-cert")) 155551037b10e427687b7115751c7d613d66459c427Gaurav Shah cert_mode = 1; 156551037b10e427687b7115751c7d613d66459c427Gaurav Shah 157551037b10e427687b7115751c7d613d66459c427Gaurav Shah fp = fopen(argv[2], "r"); 158322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 159322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah if (!fp) { 160551037b10e427687b7115751c7d613d66459c427Gaurav Shah fprintf(stderr, "Couldn't open file %s!\n", argv[2]); 161322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah return -1; 162322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah } 163322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 164551037b10e427687b7115751c7d613d66459c427Gaurav Shah if (cert_mode) { 165551037b10e427687b7115751c7d613d66459c427Gaurav Shah /* Read the certificate */ 166551037b10e427687b7115751c7d613d66459c427Gaurav Shah if (!PEM_read_X509(fp, &cert, NULL, NULL)) { 167551037b10e427687b7115751c7d613d66459c427Gaurav Shah fprintf(stderr, "Couldn't read certificate.\n"); 168551037b10e427687b7115751c7d613d66459c427Gaurav Shah goto fail; 169551037b10e427687b7115751c7d613d66459c427Gaurav Shah } 170551037b10e427687b7115751c7d613d66459c427Gaurav Shah 171551037b10e427687b7115751c7d613d66459c427Gaurav Shah /* Get the public key from the certificate. */ 172551037b10e427687b7115751c7d613d66459c427Gaurav Shah key = X509_get_pubkey(cert); 173551037b10e427687b7115751c7d613d66459c427Gaurav Shah 174551037b10e427687b7115751c7d613d66459c427Gaurav Shah /* Convert to a RSA_style key. */ 175551037b10e427687b7115751c7d613d66459c427Gaurav Shah if (!(pubkey = EVP_PKEY_get1_RSA(key))) { 176551037b10e427687b7115751c7d613d66459c427Gaurav Shah fprintf(stderr, "Couldn't convert to a RSA style key.\n"); 177551037b10e427687b7115751c7d613d66459c427Gaurav Shah goto fail; 178551037b10e427687b7115751c7d613d66459c427Gaurav Shah } 179551037b10e427687b7115751c7d613d66459c427Gaurav Shah } else { 180551037b10e427687b7115751c7d613d66459c427Gaurav Shah /* Read the pubkey in .PEM format. */ 181551037b10e427687b7115751c7d613d66459c427Gaurav Shah if (!(pubkey = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL))) { 182551037b10e427687b7115751c7d613d66459c427Gaurav Shah fprintf(stderr, "Couldn't read public key file.\n"); 183551037b10e427687b7115751c7d613d66459c427Gaurav Shah goto fail; 184551037b10e427687b7115751c7d613d66459c427Gaurav Shah } 185322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah } 186322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 187322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah if (check(pubkey)) { 188551037b10e427687b7115751c7d613d66459c427Gaurav Shah output(pubkey); 189322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah } 190322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 191322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shahfail: 192322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah X509_free(cert); 193322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah RSA_free(pubkey); 194322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah fclose(fp); 195322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah 196322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah return 0; 197322536d2f9d30f42218cc9f2ab40574557da8a9Gaurav Shah} 198