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