1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define _GNU_SOURCE /* needed for asprintf */ 18 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <sys/stat.h> 23 #include <sys/types.h> 24 #include <unistd.h> 25 26 #include <crypto_utils/android_pubkey.h> 27 28 #include <openssl/evp.h> 29 #include <openssl/objects.h> 30 #include <openssl/pem.h> 31 #include <openssl/rsa.h> 32 #include <openssl/sha.h> 33 34 static int write_public_keyfile(RSA *private_key, const char *private_key_path) 35 { 36 uint8_t key_data[ANDROID_PUBKEY_ENCODED_SIZE]; 37 BIO *bfile = NULL; 38 char *path = NULL; 39 int ret = -1; 40 41 if (asprintf(&path, "%s.pub", private_key_path) < 0) 42 goto out; 43 44 if (!android_pubkey_encode(private_key, key_data, sizeof(key_data))) 45 goto out; 46 47 bfile = BIO_new_file(path, "w"); 48 if (!bfile) 49 goto out; 50 51 BIO_write(bfile, key_data, sizeof(key_data)); 52 BIO_flush(bfile); 53 54 ret = 0; 55 out: 56 BIO_free_all(bfile); 57 free(path); 58 return ret; 59 } 60 61 static int convert_x509(const char *pem_file, const char *key_file) 62 { 63 int ret = -1; 64 FILE *f = NULL; 65 EVP_PKEY *pkey = NULL; 66 RSA *rsa = NULL; 67 X509 *cert = NULL; 68 69 if (!pem_file || !key_file) { 70 goto out; 71 } 72 73 f = fopen(pem_file, "r"); 74 if (!f) { 75 printf("Failed to open '%s'\n", pem_file); 76 goto out; 77 } 78 79 cert = PEM_read_X509(f, &cert, NULL, NULL); 80 if (!cert) { 81 printf("Failed to read PEM certificate from file '%s'\n", pem_file); 82 goto out; 83 } 84 85 pkey = X509_get_pubkey(cert); 86 if (!pkey) { 87 printf("Failed to extract public key from certificate '%s'\n", pem_file); 88 goto out; 89 } 90 91 rsa = EVP_PKEY_get1_RSA(pkey); 92 if (!rsa) { 93 printf("Failed to get the RSA public key from '%s'\n", pem_file); 94 goto out; 95 } 96 97 if (write_public_keyfile(rsa, key_file) < 0) { 98 printf("Failed to write public key\n"); 99 goto out; 100 } 101 102 ret = 0; 103 104 out: 105 if (f) { 106 fclose(f); 107 } 108 if (cert) { 109 X509_free(cert); 110 } 111 if (pkey) { 112 EVP_PKEY_free(pkey); 113 } 114 if (rsa) { 115 RSA_free(rsa); 116 } 117 118 return ret; 119 } 120 121 static int generate_key(const char *file) 122 { 123 int ret = -1; 124 FILE *f = NULL; 125 RSA* rsa = RSA_new(); 126 BIGNUM* exponent = BN_new(); 127 EVP_PKEY* pkey = EVP_PKEY_new(); 128 129 if (!pkey || !exponent || !rsa) { 130 printf("Failed to allocate key\n"); 131 goto out; 132 } 133 134 BN_set_word(exponent, RSA_F4); 135 RSA_generate_key_ex(rsa, 2048, exponent, NULL); 136 EVP_PKEY_set1_RSA(pkey, rsa); 137 138 f = fopen(file, "w"); 139 if (!f) { 140 printf("Failed to open '%s'\n", file); 141 goto out; 142 } 143 144 if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) { 145 printf("Failed to write key\n"); 146 goto out; 147 } 148 149 if (write_public_keyfile(rsa, file) < 0) { 150 printf("Failed to write public key\n"); 151 goto out; 152 } 153 154 ret = 0; 155 156 out: 157 if (f) 158 fclose(f); 159 EVP_PKEY_free(pkey); 160 RSA_free(rsa); 161 BN_free(exponent); 162 return ret; 163 } 164 165 static void usage(){ 166 printf("Usage: generate_verity_key <path-to-key> | -convert <path-to-x509-pem> <path-to-key>\n"); 167 } 168 169 int main(int argc, char *argv[]) { 170 if (argc == 2) { 171 return generate_key(argv[1]); 172 } else if (argc == 4 && !strcmp(argv[1], "-convert")) { 173 return convert_x509(argv[2], argv[3]); 174 } else { 175 usage(); 176 exit(-1); 177 } 178 } 179