1649fd550341328077e403dd2b2024a9958ae2652Geremy Condra/* 2649fd550341328077e403dd2b2024a9958ae2652Geremy Condra * Copyright (C) 2013 The Android Open Source Project 3649fd550341328077e403dd2b2024a9958ae2652Geremy Condra * 4649fd550341328077e403dd2b2024a9958ae2652Geremy Condra * Licensed under the Apache License, Version 2.0 (the "License"); 5649fd550341328077e403dd2b2024a9958ae2652Geremy Condra * you may not use this file except in compliance with the License. 6649fd550341328077e403dd2b2024a9958ae2652Geremy Condra * You may obtain a copy of the License at 7649fd550341328077e403dd2b2024a9958ae2652Geremy Condra * 8649fd550341328077e403dd2b2024a9958ae2652Geremy Condra * http://www.apache.org/licenses/LICENSE-2.0 9649fd550341328077e403dd2b2024a9958ae2652Geremy Condra * 10649fd550341328077e403dd2b2024a9958ae2652Geremy Condra * Unless required by applicable law or agreed to in writing, software 11649fd550341328077e403dd2b2024a9958ae2652Geremy Condra * distributed under the License is distributed on an "AS IS" BASIS, 12649fd550341328077e403dd2b2024a9958ae2652Geremy Condra * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13649fd550341328077e403dd2b2024a9958ae2652Geremy Condra * See the License for the specific language governing permissions and 14649fd550341328077e403dd2b2024a9958ae2652Geremy Condra * limitations under the License. 15649fd550341328077e403dd2b2024a9958ae2652Geremy Condra */ 16649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 17649fd550341328077e403dd2b2024a9958ae2652Geremy Condra#include <stdio.h> 18649fd550341328077e403dd2b2024a9958ae2652Geremy Condra#include <string.h> 19649fd550341328077e403dd2b2024a9958ae2652Geremy Condra#include <sys/types.h> 20649fd550341328077e403dd2b2024a9958ae2652Geremy Condra#include <sys/stat.h> 21649fd550341328077e403dd2b2024a9958ae2652Geremy Condra#include <unistd.h> 22649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 23649fd550341328077e403dd2b2024a9958ae2652Geremy Condra/* HACK: we need the RSAPublicKey struct 24649fd550341328077e403dd2b2024a9958ae2652Geremy Condra * but RSA_verify conflits with openssl */ 25649fd550341328077e403dd2b2024a9958ae2652Geremy Condra#define RSA_verify RSA_verify_mincrypt 26649fd550341328077e403dd2b2024a9958ae2652Geremy Condra#include "mincrypt/rsa.h" 27649fd550341328077e403dd2b2024a9958ae2652Geremy Condra#undef RSA_verify 28649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 29649fd550341328077e403dd2b2024a9958ae2652Geremy Condra#include <openssl/evp.h> 30649fd550341328077e403dd2b2024a9958ae2652Geremy Condra#include <openssl/objects.h> 31649fd550341328077e403dd2b2024a9958ae2652Geremy Condra#include <openssl/pem.h> 32649fd550341328077e403dd2b2024a9958ae2652Geremy Condra#include <openssl/rsa.h> 33649fd550341328077e403dd2b2024a9958ae2652Geremy Condra#include <openssl/sha.h> 34649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 35649fd550341328077e403dd2b2024a9958ae2652Geremy Condra// Convert OpenSSL RSA private key to android pre-computed RSAPublicKey format. 36649fd550341328077e403dd2b2024a9958ae2652Geremy Condra// Lifted from secure adb's mincrypt key generation. 37649fd550341328077e403dd2b2024a9958ae2652Geremy Condrastatic int convert_to_mincrypt_format(RSA *rsa, RSAPublicKey *pkey) 38649fd550341328077e403dd2b2024a9958ae2652Geremy Condra{ 39649fd550341328077e403dd2b2024a9958ae2652Geremy Condra int ret = -1; 40649fd550341328077e403dd2b2024a9958ae2652Geremy Condra unsigned int i; 41649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 42649fd550341328077e403dd2b2024a9958ae2652Geremy Condra if (RSA_size(rsa) != RSANUMBYTES) 43649fd550341328077e403dd2b2024a9958ae2652Geremy Condra goto out; 44649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 45649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BN_CTX* ctx = BN_CTX_new(); 46649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BIGNUM* r32 = BN_new(); 47649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BIGNUM* rr = BN_new(); 48649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BIGNUM* r = BN_new(); 49649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BIGNUM* rem = BN_new(); 50649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BIGNUM* n = BN_new(); 51649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BIGNUM* n0inv = BN_new(); 52649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 53649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BN_set_bit(r32, 32); 54649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BN_copy(n, rsa->n); 55649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BN_set_bit(r, RSANUMWORDS * 32); 56649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BN_mod_sqr(rr, r, n, ctx); 57649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BN_div(NULL, rem, n, r32, ctx); 58649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BN_mod_inverse(n0inv, rem, r32, ctx); 59649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 60649fd550341328077e403dd2b2024a9958ae2652Geremy Condra pkey->len = RSANUMWORDS; 61649fd550341328077e403dd2b2024a9958ae2652Geremy Condra pkey->n0inv = 0 - BN_get_word(n0inv); 62649fd550341328077e403dd2b2024a9958ae2652Geremy Condra for (i = 0; i < RSANUMWORDS; i++) { 63649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BN_div(rr, rem, rr, r32, ctx); 64649fd550341328077e403dd2b2024a9958ae2652Geremy Condra pkey->rr[i] = BN_get_word(rem); 65649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BN_div(n, rem, n, r32, ctx); 66649fd550341328077e403dd2b2024a9958ae2652Geremy Condra pkey->n[i] = BN_get_word(rem); 67649fd550341328077e403dd2b2024a9958ae2652Geremy Condra } 68649fd550341328077e403dd2b2024a9958ae2652Geremy Condra pkey->exponent = BN_get_word(rsa->e); 69649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 70649fd550341328077e403dd2b2024a9958ae2652Geremy Condra ret = 0; 71649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 72649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BN_free(n0inv); 73649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BN_free(n); 74649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BN_free(rem); 75649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BN_free(r); 76649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BN_free(rr); 77649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BN_free(r32); 78649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BN_CTX_free(ctx); 79649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 80649fd550341328077e403dd2b2024a9958ae2652Geremy Condraout: 81649fd550341328077e403dd2b2024a9958ae2652Geremy Condra return ret; 82649fd550341328077e403dd2b2024a9958ae2652Geremy Condra} 83649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 84649fd550341328077e403dd2b2024a9958ae2652Geremy Condrastatic int write_public_keyfile(RSA *private_key, const char *private_key_path) 85649fd550341328077e403dd2b2024a9958ae2652Geremy Condra{ 86649fd550341328077e403dd2b2024a9958ae2652Geremy Condra RSAPublicKey pkey; 87649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BIO *bfile = NULL; 88649fd550341328077e403dd2b2024a9958ae2652Geremy Condra char *path = NULL; 89649fd550341328077e403dd2b2024a9958ae2652Geremy Condra int ret = -1; 90649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 91649fd550341328077e403dd2b2024a9958ae2652Geremy Condra if (asprintf(&path, "%s.pub", private_key_path) < 0) 92649fd550341328077e403dd2b2024a9958ae2652Geremy Condra goto out; 93649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 94649fd550341328077e403dd2b2024a9958ae2652Geremy Condra if (convert_to_mincrypt_format(private_key, &pkey) < 0) 95649fd550341328077e403dd2b2024a9958ae2652Geremy Condra goto out; 96649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 97649fd550341328077e403dd2b2024a9958ae2652Geremy Condra bfile = BIO_new_file(path, "w"); 98649fd550341328077e403dd2b2024a9958ae2652Geremy Condra if (!bfile) 99649fd550341328077e403dd2b2024a9958ae2652Geremy Condra goto out; 100649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 101649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BIO_write(bfile, &pkey, sizeof(pkey)); 102649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BIO_flush(bfile); 103649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 104649fd550341328077e403dd2b2024a9958ae2652Geremy Condra ret = 0; 105649fd550341328077e403dd2b2024a9958ae2652Geremy Condraout: 106649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BIO_free_all(bfile); 107649fd550341328077e403dd2b2024a9958ae2652Geremy Condra free(path); 108649fd550341328077e403dd2b2024a9958ae2652Geremy Condra return ret; 109649fd550341328077e403dd2b2024a9958ae2652Geremy Condra} 110649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 1118d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanenstatic int convert_x509(const char *pem_file, const char *key_file) 1128d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen{ 1138d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen int ret = -1; 1148d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen FILE *f = NULL; 1158d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen EVP_PKEY *pkey = NULL; 1168d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen RSA *rsa = NULL; 1178d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen X509 *cert = NULL; 1188d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen 1198d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen if (!pem_file || !key_file) { 1208d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen goto out; 1218d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen } 1228d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen 1238d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen f = fopen(pem_file, "r"); 1248d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen if (!f) { 1258d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen printf("Failed to open '%s'\n", pem_file); 1268d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen goto out; 1278d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen } 1288d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen 1298d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen cert = PEM_read_X509(f, &cert, NULL, NULL); 1308d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen if (!cert) { 1318d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen printf("Failed to read PEM certificate from file '%s'\n", pem_file); 1328d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen goto out; 1338d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen } 1348d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen 1358d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen pkey = X509_get_pubkey(cert); 1368d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen if (!pkey) { 1378d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen printf("Failed to extract public key from certificate '%s'\n", pem_file); 1388d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen goto out; 1398d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen } 1408d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen 1418d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen rsa = EVP_PKEY_get1_RSA(pkey); 1428d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen if (!rsa) { 1438d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen printf("Failed to get the RSA public key from '%s'\n", pem_file); 1448d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen goto out; 1458d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen } 1468d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen 1478d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen if (write_public_keyfile(rsa, key_file) < 0) { 1488d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen printf("Failed to write public key\n"); 1498d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen goto out; 1508d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen } 1518d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen 1528d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen ret = 0; 1538d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen 1548d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanenout: 1558d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen if (f) { 1568d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen fclose(f); 1578d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen } 1588d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen if (cert) { 1598d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen X509_free(cert); 1608d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen } 1618d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen if (pkey) { 1628d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen EVP_PKEY_free(pkey); 1638d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen } 1648d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen if (rsa) { 1658d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen RSA_free(rsa); 1668d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen } 1678d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen 1688d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen return ret; 1698d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen} 1708d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen 171649fd550341328077e403dd2b2024a9958ae2652Geremy Condrastatic int generate_key(const char *file) 172649fd550341328077e403dd2b2024a9958ae2652Geremy Condra{ 173649fd550341328077e403dd2b2024a9958ae2652Geremy Condra int ret = -1; 174649fd550341328077e403dd2b2024a9958ae2652Geremy Condra FILE *f = NULL; 175649fd550341328077e403dd2b2024a9958ae2652Geremy Condra RSA* rsa = RSA_new(); 176649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BIGNUM* exponent = BN_new(); 177649fd550341328077e403dd2b2024a9958ae2652Geremy Condra EVP_PKEY* pkey = EVP_PKEY_new(); 178649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 179649fd550341328077e403dd2b2024a9958ae2652Geremy Condra if (!pkey || !exponent || !rsa) { 180649fd550341328077e403dd2b2024a9958ae2652Geremy Condra printf("Failed to allocate key\n"); 181649fd550341328077e403dd2b2024a9958ae2652Geremy Condra goto out; 182649fd550341328077e403dd2b2024a9958ae2652Geremy Condra } 183649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 184649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BN_set_word(exponent, RSA_F4); 185649fd550341328077e403dd2b2024a9958ae2652Geremy Condra RSA_generate_key_ex(rsa, 2048, exponent, NULL); 186649fd550341328077e403dd2b2024a9958ae2652Geremy Condra EVP_PKEY_set1_RSA(pkey, rsa); 187649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 188649fd550341328077e403dd2b2024a9958ae2652Geremy Condra f = fopen(file, "w"); 189649fd550341328077e403dd2b2024a9958ae2652Geremy Condra if (!f) { 190649fd550341328077e403dd2b2024a9958ae2652Geremy Condra printf("Failed to open '%s'\n", file); 191649fd550341328077e403dd2b2024a9958ae2652Geremy Condra goto out; 192649fd550341328077e403dd2b2024a9958ae2652Geremy Condra } 193649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 194649fd550341328077e403dd2b2024a9958ae2652Geremy Condra if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) { 195649fd550341328077e403dd2b2024a9958ae2652Geremy Condra printf("Failed to write key\n"); 196649fd550341328077e403dd2b2024a9958ae2652Geremy Condra goto out; 197649fd550341328077e403dd2b2024a9958ae2652Geremy Condra } 198649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 199649fd550341328077e403dd2b2024a9958ae2652Geremy Condra if (write_public_keyfile(rsa, file) < 0) { 200649fd550341328077e403dd2b2024a9958ae2652Geremy Condra printf("Failed to write public key\n"); 201649fd550341328077e403dd2b2024a9958ae2652Geremy Condra goto out; 202649fd550341328077e403dd2b2024a9958ae2652Geremy Condra } 203649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 204649fd550341328077e403dd2b2024a9958ae2652Geremy Condra ret = 0; 205649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 206649fd550341328077e403dd2b2024a9958ae2652Geremy Condraout: 207649fd550341328077e403dd2b2024a9958ae2652Geremy Condra if (f) 208649fd550341328077e403dd2b2024a9958ae2652Geremy Condra fclose(f); 209649fd550341328077e403dd2b2024a9958ae2652Geremy Condra EVP_PKEY_free(pkey); 210649fd550341328077e403dd2b2024a9958ae2652Geremy Condra RSA_free(rsa); 211649fd550341328077e403dd2b2024a9958ae2652Geremy Condra BN_free(exponent); 212649fd550341328077e403dd2b2024a9958ae2652Geremy Condra return ret; 213649fd550341328077e403dd2b2024a9958ae2652Geremy Condra} 214649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 215649fd550341328077e403dd2b2024a9958ae2652Geremy Condrastatic void usage(){ 2168d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen printf("Usage: generate_verity_key <path-to-key> | -convert <path-to-x509-pem> <path-to-key>\n"); 217649fd550341328077e403dd2b2024a9958ae2652Geremy Condra} 218649fd550341328077e403dd2b2024a9958ae2652Geremy Condra 219649fd550341328077e403dd2b2024a9958ae2652Geremy Condraint main(int argc, char *argv[]) { 2208d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen if (argc == 2) { 2218d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen return generate_key(argv[1]); 2228d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen } else if (argc == 4 && !strcmp(argv[1], "-convert")) { 2238d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen return convert_x509(argv[2], argv[3]); 2248d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen } else { 225649fd550341328077e403dd2b2024a9958ae2652Geremy Condra usage(); 226649fd550341328077e403dd2b2024a9958ae2652Geremy Condra exit(-1); 227649fd550341328077e403dd2b2024a9958ae2652Geremy Condra } 2288d7e92406cdccb94f853d9ffcdc95dcdde37b47aSami Tolvanen} 229