blob: 837303cbe717b2c2624d33708cc0574436dbc28e [file] [log] [blame]
Gaurav Shah322536d2010-01-28 15:01:23 -08001/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
6/* C port of DumpPublicKey.java from the Android Open source project with
7 * support for additional RSA key sizes. (platform/system/core,git/libmincrypt
8 * /tools/DumpPublicKey.java). Uses the OpenSSL X509 and BIGNUM library.
9 */
10
Gaurav Shahed9c96a2010-03-30 18:56:07 -070011#include <stdint.h>
Gaurav Shah322536d2010-01-28 15:01:23 -080012#include <openssl/bn.h>
13#include <openssl/evp.h>
14#include <openssl/pem.h>
15#include <openssl/x509.h>
16#include <string.h>
17#include <unistd.h>
18
19/* Command line tool to extract RSA public keys from X.509 certificates
20 * and output a pre-processed version of keys for use by RSA verification
21 * routines.
22 */
23
24int check(RSA* key) {
25 int public_exponent = BN_get_word(key->e);
26 int modulus = BN_num_bits(key->n);
27
28 if (public_exponent != 65537) {
29 fprintf(stderr, "WARNING: Public exponent should be 65537 (but is %d).\n",
30 public_exponent);
31 }
32
33 if (modulus != 1024 && modulus != 2048 && modulus != 4096
34 && modulus != 8192) {
35 fprintf(stderr, "ERROR: Unknown modulus length = %d.\n", modulus);
36 return 0;
37 }
38 return 1;
39}
40
41/* Pre-processes and outputs RSA public key to standard out.
42 */
43void output(RSA* key) {
44 int i, nwords;
45 BIGNUM *N = key->n;
Gaurav Shah48ed9b82010-03-11 16:31:35 -080046 BIGNUM *Big1 = NULL, *Big2 = NULL, *Big32 = NULL, *BigMinus1 = NULL;
47 BIGNUM *B = NULL;
48 BIGNUM *N0inv= NULL, *R = NULL, *RR = NULL, *RRTemp = NULL, *NnumBits = NULL;
49 BIGNUM *n = NULL, *rr = NULL;
Gaurav Shah322536d2010-01-28 15:01:23 -080050 BN_CTX *bn_ctx = BN_CTX_new();
51 uint32_t n0invout;
52
53 N = key->n;
54 /* Output size of RSA key in 32-bit words */
55 nwords = BN_num_bits(N) / 32;
Gaurav Shah16ca3242010-03-11 13:41:25 -080056 if (-1 == write(1, &nwords, sizeof(nwords)))
57 goto failure;
58
Gaurav Shah322536d2010-01-28 15:01:23 -080059
60 /* Initialize BIGNUMs */
61 Big1 = BN_new();
62 Big2 = BN_new();
63 Big32 = BN_new();
64 BigMinus1 = BN_new();
65 N0inv= BN_new();
66 R = BN_new();
67 RR = BN_new();
68 RRTemp = BN_new();
69 NnumBits = BN_new();
70 n = BN_new();
71 rr = BN_new();
72
73
74 BN_set_word(Big1, 1L);
75 BN_set_word(Big2, 2L);
76 BN_set_word(Big32, 32L);
77 BN_sub(BigMinus1, Big1, Big2);
78
79 B = BN_new();
80 BN_exp(B, Big2, Big32, bn_ctx); /* B = 2^32 */
81
82 /* Calculate and output N0inv = -1 / N[0] mod 2^32 */
83 BN_mod_inverse(N0inv, N, B, bn_ctx);
84 BN_sub(N0inv, B, N0inv);
85 n0invout = BN_get_word(N0inv);
Gaurav Shah16ca3242010-03-11 13:41:25 -080086 if (-1 == write(1, &n0invout, sizeof(n0invout)))
87 goto failure;
Gaurav Shah322536d2010-01-28 15:01:23 -080088
89 /* Calculate R = 2^(# of key bits) */
90 BN_set_word(NnumBits, BN_num_bits(N));
91 BN_exp(R, Big2, NnumBits, bn_ctx);
92
93 /* Calculate RR = R^2 mod N */
94 BN_copy(RR, R);
95 BN_mul(RRTemp, RR, R, bn_ctx);
96 BN_mod(RR, RRTemp, N, bn_ctx);
97
98
99 /* Write out modulus as little endian array of integers. */
100 for (i = 0; i < nwords; ++i) {
101 uint32_t nout;
102
103 BN_mod(n, N, B, bn_ctx); /* n = N mod B */
104 nout = BN_get_word(n);
Gaurav Shah16ca3242010-03-11 13:41:25 -0800105 if (-1 == write(1, &nout, sizeof(nout)))
106 goto failure;
Gaurav Shah322536d2010-01-28 15:01:23 -0800107
108 BN_rshift(N, N, 32); /* N = N/B */
109 }
110
111 /* Write R^2 as little endian array of integers. */
112 for (i = 0; i < nwords; ++i) {
113 uint32_t rrout;
114
115 BN_mod(rr, RR, B, bn_ctx); /* rr = RR mod B */
116 rrout = BN_get_word(rr);
Gaurav Shah16ca3242010-03-11 13:41:25 -0800117 if (-1 == write(1, &rrout, sizeof(rrout)))
118 goto failure;
Gaurav Shah322536d2010-01-28 15:01:23 -0800119
120 BN_rshift(RR, RR, 32); /* RR = RR/B */
121 }
122
Gaurav Shah16ca3242010-03-11 13:41:25 -0800123failure:
Gaurav Shah322536d2010-01-28 15:01:23 -0800124 /* Free BIGNUMs. */
125 BN_free(Big1);
126 BN_free(Big2);
127 BN_free(Big32);
128 BN_free(BigMinus1);
129 BN_free(N0inv);
130 BN_free(R);
131 BN_free(RRTemp);
132 BN_free(NnumBits);
133 BN_free(n);
134 BN_free(rr);
135
136}
137
138int main(int argc, char* argv[]) {
139 FILE* fp;
140 X509* cert = NULL;
141 RSA* pubkey = NULL;
142 EVP_PKEY* key;
143
144 if (argc != 2) {
145 fprintf(stderr, "Usage: %s <certfile>\n", argv[0]);
146 return -1;
147 }
148
149 fp = fopen(argv[1], "r");
150
151 if (!fp) {
152 fprintf(stderr, "Couldn't open certificate file!\n");
153 return -1;
154 }
155
156 /* Read the certificate */
157 if (!PEM_read_X509(fp, &cert, NULL, NULL)) {
158 fprintf(stderr, "Couldn't read certificate.\n");
159 goto fail;
160 }
161
162 /* Get the public key from the certificate. */
163 key = X509_get_pubkey(cert);
164
165 /* Convert to a RSA_style key. */
166 if (!(pubkey = EVP_PKEY_get1_RSA(key))) {
167 fprintf(stderr, "Couldn't convert to a RSA style key.\n");
168 goto fail;
169 }
170
171 if (check(pubkey)) {
172 output (pubkey);
173 }
174
175fail:
176 X509_free(cert);
177 RSA_free(pubkey);
178 fclose(fp);
179
180 return 0;
181}