OSDN Git Service

am ea56ba43: net_test environment changes
[android-x86/system-extras.git] / verity / generate_verity_key.c
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 #include <stdio.h>
18 #include <string.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22
23 /* HACK: we need the RSAPublicKey struct
24  * but RSA_verify conflits with openssl */
25 #define RSA_verify RSA_verify_mincrypt
26 #include "mincrypt/rsa.h"
27 #undef RSA_verify
28
29 #include <openssl/evp.h>
30 #include <openssl/objects.h>
31 #include <openssl/pem.h>
32 #include <openssl/rsa.h>
33 #include <openssl/sha.h>
34
35 // Convert OpenSSL RSA private key to android pre-computed RSAPublicKey format.
36 // Lifted from secure adb's mincrypt key generation.
37 static int convert_to_mincrypt_format(RSA *rsa, RSAPublicKey *pkey)
38 {
39     int ret = -1;
40     unsigned int i;
41
42     if (RSA_size(rsa) != RSANUMBYTES)
43         goto out;
44
45     BN_CTX* ctx = BN_CTX_new();
46     BIGNUM* r32 = BN_new();
47     BIGNUM* rr = BN_new();
48     BIGNUM* r = BN_new();
49     BIGNUM* rem = BN_new();
50     BIGNUM* n = BN_new();
51     BIGNUM* n0inv = BN_new();
52
53     BN_set_bit(r32, 32);
54     BN_copy(n, rsa->n);
55     BN_set_bit(r, RSANUMWORDS * 32);
56     BN_mod_sqr(rr, r, n, ctx);
57     BN_div(NULL, rem, n, r32, ctx);
58     BN_mod_inverse(n0inv, rem, r32, ctx);
59
60     pkey->len = RSANUMWORDS;
61     pkey->n0inv = 0 - BN_get_word(n0inv);
62     for (i = 0; i < RSANUMWORDS; i++) {
63         BN_div(rr, rem, rr, r32, ctx);
64         pkey->rr[i] = BN_get_word(rem);
65         BN_div(n, rem, n, r32, ctx);
66         pkey->n[i] = BN_get_word(rem);
67     }
68     pkey->exponent = BN_get_word(rsa->e);
69
70     ret = 0;
71
72     BN_free(n0inv);
73     BN_free(n);
74     BN_free(rem);
75     BN_free(r);
76     BN_free(rr);
77     BN_free(r32);
78     BN_CTX_free(ctx);
79
80 out:
81     return ret;
82 }
83
84 static int write_public_keyfile(RSA *private_key, const char *private_key_path)
85 {
86     RSAPublicKey pkey;
87     BIO *bfile = NULL;
88     char *path = NULL;
89     int ret = -1;
90
91     if (asprintf(&path, "%s.pub", private_key_path) < 0)
92         goto out;
93
94     if (convert_to_mincrypt_format(private_key, &pkey) < 0)
95         goto out;
96
97     bfile = BIO_new_file(path, "w");
98     if (!bfile)
99         goto out;
100
101     BIO_write(bfile, &pkey, sizeof(pkey));
102     BIO_flush(bfile);
103
104     ret = 0;
105 out:
106     BIO_free_all(bfile);
107     free(path);
108     return ret;
109 }
110
111 static int convert_x509(const char *pem_file, const char *key_file)
112 {
113     int ret = -1;
114     FILE *f = NULL;
115     EVP_PKEY *pkey = NULL;
116     RSA *rsa = NULL;
117     X509 *cert = NULL;
118
119     if (!pem_file || !key_file) {
120         goto out;
121     }
122
123     f = fopen(pem_file, "r");
124     if (!f) {
125         printf("Failed to open '%s'\n", pem_file);
126         goto out;
127     }
128
129     cert = PEM_read_X509(f, &cert, NULL, NULL);
130     if (!cert) {
131         printf("Failed to read PEM certificate from file '%s'\n", pem_file);
132         goto out;
133     }
134
135     pkey = X509_get_pubkey(cert);
136     if (!pkey) {
137         printf("Failed to extract public key from certificate '%s'\n", pem_file);
138         goto out;
139     }
140
141     rsa = EVP_PKEY_get1_RSA(pkey);
142     if (!rsa) {
143         printf("Failed to get the RSA public key from '%s'\n", pem_file);
144         goto out;
145     }
146
147     if (write_public_keyfile(rsa, key_file) < 0) {
148         printf("Failed to write public key\n");
149         goto out;
150     }
151
152     ret = 0;
153
154 out:
155     if (f) {
156         fclose(f);
157     }
158     if (cert) {
159         X509_free(cert);
160     }
161     if (pkey) {
162         EVP_PKEY_free(pkey);
163     }
164     if (rsa) {
165         RSA_free(rsa);
166     }
167
168     return ret;
169 }
170
171 static int generate_key(const char *file)
172 {
173     int ret = -1;
174     FILE *f = NULL;
175     RSA* rsa = RSA_new();
176     BIGNUM* exponent = BN_new();
177     EVP_PKEY* pkey = EVP_PKEY_new();
178
179     if (!pkey || !exponent || !rsa) {
180         printf("Failed to allocate key\n");
181         goto out;
182     }
183
184     BN_set_word(exponent, RSA_F4);
185     RSA_generate_key_ex(rsa, 2048, exponent, NULL);
186     EVP_PKEY_set1_RSA(pkey, rsa);
187
188     f = fopen(file, "w");
189     if (!f) {
190         printf("Failed to open '%s'\n", file);
191         goto out;
192     }
193
194     if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) {
195         printf("Failed to write key\n");
196         goto out;
197     }
198
199     if (write_public_keyfile(rsa, file) < 0) {
200         printf("Failed to write public key\n");
201         goto out;
202     }
203
204     ret = 0;
205
206 out:
207     if (f)
208         fclose(f);
209     EVP_PKEY_free(pkey);
210     RSA_free(rsa);
211     BN_free(exponent);
212     return ret;
213 }
214
215 static void usage(){
216     printf("Usage: generate_verity_key <path-to-key> | -convert <path-to-x509-pem> <path-to-key>\n");
217 }
218
219 int main(int argc, char *argv[]) {
220     if (argc == 2) {
221         return generate_key(argv[1]);
222     } else if (argc == 4 && !strcmp(argv[1], "-convert")) {
223         return convert_x509(argv[2], argv[3]);
224     } else {
225         usage();
226         exit(-1);
227     }
228 }