OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
RsaTool.c
Go to the documentation of this file.
1/* 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/* C port of DumpPublicKey.java from the Android Open source project with
6 * support for additional RSA key sizes. (platform/system/core,git/libmincrypt
7 * /tools/DumpPublicKey.java). Uses the OpenSSL X509 and BIGNUM library.
8 */
9#include <limits.h>
10#include <stdint.h>
11#include <string.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include "openssl_compat.h"
15/* Command line tool to extract RSA public keys from X.509 certificates
16 * and output a pre-processed version of keys for use by RSA verification
17 * routines.
18 */
19static int check(RSA* key) {
20 const BIGNUM *n, *e;
21 int public_exponent, modulus;
22 RSA_get0_key(key, &n, &e, NULL);
23 public_exponent = BN_get_word(e);
24 modulus = BN_num_bits(n);
25 if (public_exponent != 3 && public_exponent != 65537) {
26 fprintf(stderr,
27 "WARNING: Public exponent should be 3 or 65537 (but is %d).\n",
28 public_exponent);
29 }
30 if (modulus != 1024 && modulus != 2048 && modulus != 3072 && modulus != 4096
31 && modulus != 8192) {
32 fprintf(stderr, "ERROR: Unknown modulus length = %d.\n", modulus);
33 return 0;
34 }
35 return 1;
36}
37static void native_to_big(unsigned char* data, size_t size) {
38 size_t i, tmp = 1;
39 if (*(unsigned char *)&tmp == 1) {
40 fprintf(stderr, "WARNING: Assuming little endian encoding.\n");
41 for (i = 0; i < size / 2; ++i) {
42 tmp = data[i];
43 data[i] = data[size - i - 1];
44 data[size - i - 1] = tmp;
45 }
46 } else {
47 fprintf(stderr, "WARNING: Assuming big endian encoding.\n");
48 }
49}
50typedef void (*t_data_printer)(void* context, void* data, size_t size);
51static void print_data(void* context, void* data, size_t size) {
52 size_t i;
53 (void)context;
54 static size_t block = 0;
55 if (data == NULL) {
56 if (block > 0)
57 puts("");
58 } else {
59 for (i = 0; i < size; ++i, ++block) {
60 if (block == 12) {
61 puts(",");
62 block = 0;
63 }
64 printf("%s0x%02x", block == 0 ? "" : ", ", ((uint8_t *)data)[i]);
65 }
66 }
67}
68static void write_data(void* context, void* data, size_t size) {
69 if (size > 0 && fwrite(data, size, 1, (FILE *)context) != 1) {
70 abort();
71 }
72}
73/* Pre-processes and outputs RSA public key to standard out.
74 */
75static void output(RSA* key, t_data_printer printer, void *printer_ctx) {
76 uint64_t i, nwords;
77 const BIGNUM *key_n;
78 BIGNUM *N = NULL;
79 BIGNUM *Big1 = NULL, *Big2 = NULL, *Big64 = NULL, *BigMinus1 = NULL;
80 BIGNUM *B = NULL;
81 BIGNUM *N0inv= NULL, *R = NULL, *RR = NULL, *RRTemp = NULL, *NnumBits = NULL;
82 BIGNUM *n = NULL, *rr = NULL;
83 BN_CTX *bn_ctx = BN_CTX_new();
84 uint64_t n0invout;
85 /* Output size of RSA key in 64-bit words */
86 nwords = RSA_size(key) / 8;
87 if (nwords > UINT16_MAX) return;
88 printer(printer_ctx, &nwords, sizeof(nwords));
89 /* Initialize BIGNUMs */
90 RSA_get0_key(key, &key_n, NULL, NULL);
91 N = BN_dup(key_n);
92 Big1 = BN_new();
93 Big2 = BN_new();
94 Big64 = BN_new();
95 BigMinus1 = BN_new();
96 N0inv= BN_new();
97 R = BN_new();
98 RR = BN_new();
99 RRTemp = BN_new();
100 NnumBits = BN_new();
101 n = BN_new();
102 rr = BN_new();
103 BN_set_word(Big1, 1L);
104 BN_set_word(Big2, 2L);
105 BN_set_word(Big64, 64L);
106 BN_sub(BigMinus1, Big1, Big2);
107 B = BN_new();
108 BN_exp(B, Big2, Big64, bn_ctx); /* B = 2^64 */
109 /* Calculate and output N0inv = -1 / N[0] mod 2^64 */
110 BN_mod_inverse(N0inv, N, B, bn_ctx);
111 BN_sub(N0inv, B, N0inv);
112 n0invout = (uint64_t) BN_get_word(N0inv);
113 BN_rshift(N0inv, N0inv, 32);
114 n0invout |= (uint64_t) BN_get_word(N0inv) << 32ULL;
115 printer(printer_ctx, &n0invout, sizeof(n0invout));
116 /* Calculate R = 2^(# of key bits) */
117 BN_set_word(NnumBits, BN_num_bits(N));
118 BN_exp(R, Big2, NnumBits, bn_ctx);
119 /* Calculate RR = R^2 mod N */
120 BN_copy(RR, R);
121 BN_mul(RRTemp, RR, R, bn_ctx);
122 BN_mod(RR, RRTemp, N, bn_ctx);
123 /* Write out modulus as little endian array of integers. */
124 for (i = 0; i < nwords*2; ++i) {
125 uint32_t nout;
126 BN_mod(n, N, B, bn_ctx); /* n = N mod B */
127 nout = BN_get_word(n);
128 BN_rshift(N, N, 32); /* N = N/B */
129 printer(printer_ctx, &nout, sizeof(nout));
130 }
131 /* Write R^2 as little endian array of integers. */
132 for (i = 0; i < nwords*2; ++i) {
133 uint32_t rrout;
134 BN_mod(rr, RR, B, bn_ctx); /* rr = RR mod B */
135 rrout = BN_get_word(rr);
136 BN_rshift(RR, RR, 32); /* RR = RR/B */
137 printer(printer_ctx, &rrout, sizeof(rrout));
138 }
139 /* print terminator */
140 printer(printer_ctx, NULL, 0);
141 /* Free BIGNUMs. */
142 BN_free(N);
143 BN_free(Big1);
144 BN_free(Big2);
145 BN_free(Big64);
146 BN_free(BigMinus1);
147 BN_free(N0inv);
148 BN_free(R);
149 BN_free(RRTemp);
150 BN_free(NnumBits);
151 BN_free(n);
152 BN_free(rr);
153}
154uint8_t* read_file(FILE *fp, unsigned int *size) {
155 long fsize = 0;
156 uint8_t *data = NULL;
157 if (fseek(fp, 0, SEEK_END)) return NULL;
158 if ((fsize = ftell(fp)) <= 0 || fsize > UINT_MAX) return NULL;
159 if (fseek(fp, 0, SEEK_SET)) return NULL;
160 *size = (unsigned int)fsize;
161 if (!(data = malloc(fsize))) return NULL;
162 if (fread(data, fsize, 1, fp) == 1) return data;
163 free(data);
164 return NULL;
165}
166int sign_file(FILE* fp, const char* sigfile, const char *pubkfile) {
167 RSA* rsa = NULL;
168 BIGNUM* bn = NULL;
169 EVP_PKEY* key = NULL;
170 const EVP_MD* md = NULL;
171 EVP_MD_CTX* ctx = NULL;
172 FILE* sigf = NULL;
173 FILE* pubkf = NULL;
174 uint8_t* fp_data = NULL;
175 unsigned int fp_size = 0;
176 uint8_t signature[256];
177 unsigned int signature_size;
178 int result = -1;
179
180 if (!(fp_data = read_file(fp, &fp_size))) goto done;
181 if (!(rsa = RSA_new())) goto done;
182 if (!(bn = BN_new())) goto done;
183 if (!(md = EVP_sha256())) goto done;
184 if (!(key = EVP_PKEY_new())) goto done;
185 if (!(ctx = EVP_MD_CTX_create())) goto done;
186 if (!BN_set_word(bn, RSA_F4)) goto done;
187 if (!RSA_generate_key_ex(rsa, 2048, bn, NULL)) goto done;
188 if (!EVP_PKEY_set1_RSA(key, rsa)) goto done;
189 if (EVP_PKEY_size(key) != sizeof(signature)) goto done;
190 if (!EVP_SignInit(ctx, md)) goto done;
191 if (!EVP_SignUpdate(ctx, fp_data, fp_size)) goto done;
192 if (!EVP_SignFinal(ctx, &signature[0], &signature_size, key)) goto done;
193
194 sigf = fopen(sigfile, "wb");
195 if (!sigf) goto done;
196 if (fwrite(signature, signature_size, 1, sigf) != 1) goto done;
197 pubkf = fopen(pubkfile, "wb");
198 if (!pubkf) goto done;
199 output(rsa, write_data, pubkf);
200 result = 0;
201
202done:
203 RSA_free(rsa);
204 BN_free(bn);
205 EVP_PKEY_free(key);
206 EVP_MD_CTX_cleanup(ctx);
207 free(fp_data);
208 if (sigf) fclose(sigf);
209 if (pubkf) fclose(pubkf);
210
211 return result;
212}
213enum {
220int main(int argc, char* argv[]) {
221 int mode = INVALID_MODE;
222 FILE* fp;
223 X509* cert = NULL;
224 BIGNUM *mod = NULL;
225 BIGNUM *exp = NULL;
226 RSA* pubkey = NULL;
227 EVP_PKEY* key = NULL;
228 char* progname;
229 long size;
230 if (argc == 3) {
231 if (!strcmp(argv[1], "-cert"))
232 mode = CERT_MODE;
233 else if (!strcmp(argv[1], "-pub"))
234 mode = PEM_MODE;
235 else if (!strcmp(argv[1], "-raw"))
236 mode = RAW_MODE;
237 } else if (argc == 5) {
238 if (!strcmp(argv[1], "-sign"))
239 mode = SIGN_MODE;
240 }
241 if (mode == INVALID_MODE) {
242 progname = strrchr(argv[0], '/');
243 if (progname)
244 progname++;
245 else
246 progname = argv[0];
247 fprintf(stderr, "Usage: %s <-cert | -pub | -raw> <file>\n", progname);
248 fprintf(stderr, "Usage: %s -sign <file> <signature> <pubkey>\n", progname);
249 return -1;
250 }
251 fp = fopen(argv[2], "r");
252 if (!fp) {
253 fprintf(stderr, "Couldn't open file %s!\n", argv[2]);
254 return -1;
255 }
256
257 if (mode == SIGN_MODE) {
258 int ret = sign_file(fp, argv[3], argv[4]);
259 fclose (fp);
260 return ret;
261 }
262
263 if (mode == CERT_MODE) {
264 /* Read the certificate */
265 if (!PEM_read_X509(fp, &cert, NULL, NULL)) {
266 fprintf(stderr, "Couldn't read certificate.\n");
267 goto fail;
268 }
269 /* Get the public key from the certificate. */
270 key = X509_get_pubkey(cert);
271 /* Convert to a RSA_style key. */
272 if (!(pubkey = EVP_PKEY_get1_RSA(key))) {
273 fprintf(stderr, "Couldn't convert to a RSA style key.\n");
274 goto fail;
275 }
276 } else if (mode == PEM_MODE) {
277 /* Read the pubkey in .PEM format. */
278 if (!(pubkey = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL))) {
279 fprintf(stderr, "Couldn't read public key file.\n");
280 goto fail;
281 }
282 } else {
283 /* It is unimportant which exponent is used. */
284 static unsigned char expraw[4] = {0, 0, 0, 3};
285 static unsigned char modraw[1024];
286 if (fseek (fp, 0, SEEK_END) != 0
287 || (size = ftell(fp)) < 0
288 || fseek(fp, 0, SEEK_SET) != 0) {
289 fprintf(stderr, "Couldn't read modulus size.\n");
290 goto fail;
291 }
292 if ((size_t)size > sizeof(modraw)) {
293 fprintf(stderr, "Unsupported modulus size %ld.\n", size);
294 goto fail;
295 }
296 if (fread(modraw, size, 1, fp) != 1) {
297 fprintf(stderr, "Couldn't read modulus number.\n");
298 goto fail;
299 }
300 native_to_big(modraw, (size_t)size);
301 if (!(mod = BN_bin2bn(modraw, (int)size, NULL))) {
302 fprintf(stderr, "Couldn't create modulus number.\n");
303 goto fail;
304 }
305 if (!(exp = BN_bin2bn(expraw, sizeof(expraw), NULL))) {
306 fprintf(stderr, "Couldn't create public exp number.\n");
307 goto fail;
308 }
309 if (!(pubkey = RSA_new()) || !RSA_set0_key(pubkey, mod, exp, NULL)) {
310 fprintf(stderr, "Couldn't create rsa public key.\n");
311 goto fail;
312 }
313 /* RSA context owns its numbers. */
314 mod = exp = NULL;
315 }
316 if (check(pubkey)) {
317 output(pubkey, print_data, NULL);
318 }
319fail:
320 X509_free(cert);
321 BN_free(mod);
322 BN_free(exp);
323 RSA_free(pubkey);
324 EVP_PKEY_free(key);
325 fclose(fp);
326 return 0;
327}
UINT8 signature[3]
Definition BmfFile.h:125
UINT32 size
@ INVALID_MODE
Definition RsaTool.c:214
@ RAW_MODE
Definition RsaTool.c:217
@ CERT_MODE
Definition RsaTool.c:215
@ PEM_MODE
Definition RsaTool.c:216
@ SIGN_MODE
Definition RsaTool.c:218
void(* t_data_printer)(void *context, void *data, size_t size)
Definition RsaTool.c:50
int sign_file(FILE *fp, const char *sigfile, const char *pubkfile)
Definition RsaTool.c:166
uint8_t * read_file(FILE *fp, unsigned int *size)
Definition RsaTool.c:154
#define UINT16_MAX
Definition Ubsan.h:114
#define uint64_t
Definition Ubsan.h:60
int main()
Definition acdtinfo.c:181
UINT8 uint8_t
UINT32 uint32_t
UINT64 uint64_t
#define N
Definition lzss.c:65
#define malloc(Size)
Definition lzss.h:49
#define free(Ptr)
Definition lzss.h:50