OSDN Git Service

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