dumpRSAPublicKey.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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 <openssl/pem.h>
  10. #include <stdint.h>
  11. #include <string.h>
  12. #include <unistd.h>
  13. /* Command line tool to extract RSA public keys from X.509 certificates
  14. * and output a pre-processed version of keys for use by RSA verification
  15. * routines.
  16. */
  17. int check(RSA* key) {
  18. int public_exponent = BN_get_word(key->e);
  19. int modulus = BN_num_bits(key->n);
  20. if (public_exponent != 65537) {
  21. fprintf(stderr, "WARNING: Public exponent should be 65537 (but is %d).\n",
  22. public_exponent);
  23. }
  24. if (modulus != 1024 && modulus != 2048 && modulus != 4096
  25. && modulus != 8192) {
  26. fprintf(stderr, "ERROR: Unknown modulus length = %d.\n", modulus);
  27. return 0;
  28. }
  29. return 1;
  30. }
  31. /* Pre-processes and outputs RSA public key to standard out.
  32. */
  33. void output(RSA* key) {
  34. int i, nwords;
  35. BIGNUM *N = key->n;
  36. BIGNUM *Big1 = NULL, *Big2 = NULL, *Big32 = NULL, *BigMinus1 = NULL;
  37. BIGNUM *B = NULL;
  38. BIGNUM *N0inv= NULL, *R = NULL, *RR = NULL, *RRTemp = NULL, *NnumBits = NULL;
  39. BIGNUM *n = NULL, *rr = NULL;
  40. BN_CTX *bn_ctx = BN_CTX_new();
  41. uint32_t n0invout;
  42. N = key->n;
  43. /* Output size of RSA key in 32-bit words */
  44. nwords = BN_num_bits(N) / 32;
  45. if (-1 == write(1, &nwords, sizeof(nwords)))
  46. goto failure;
  47. /* Initialize BIGNUMs */
  48. Big1 = BN_new();
  49. Big2 = BN_new();
  50. Big32 = BN_new();
  51. BigMinus1 = BN_new();
  52. N0inv= BN_new();
  53. R = BN_new();
  54. RR = BN_new();
  55. RRTemp = BN_new();
  56. NnumBits = BN_new();
  57. n = BN_new();
  58. rr = BN_new();
  59. BN_set_word(Big1, 1L);
  60. BN_set_word(Big2, 2L);
  61. BN_set_word(Big32, 32L);
  62. BN_sub(BigMinus1, Big1, Big2);
  63. B = BN_new();
  64. BN_exp(B, Big2, Big32, bn_ctx); /* B = 2^32 */
  65. /* Calculate and output N0inv = -1 / N[0] mod 2^32 */
  66. BN_mod_inverse(N0inv, N, B, bn_ctx);
  67. BN_sub(N0inv, B, N0inv);
  68. n0invout = BN_get_word(N0inv);
  69. if (-1 == write(1, &n0invout, sizeof(n0invout)))
  70. goto failure;
  71. /* Calculate R = 2^(# of key bits) */
  72. BN_set_word(NnumBits, BN_num_bits(N));
  73. BN_exp(R, Big2, NnumBits, bn_ctx);
  74. /* Calculate RR = R^2 mod N */
  75. BN_copy(RR, R);
  76. BN_mul(RRTemp, RR, R, bn_ctx);
  77. BN_mod(RR, RRTemp, N, bn_ctx);
  78. /* Write out modulus as little endian array of integers. */
  79. for (i = 0; i < nwords; ++i) {
  80. uint32_t nout;
  81. BN_mod(n, N, B, bn_ctx); /* n = N mod B */
  82. nout = BN_get_word(n);
  83. if (-1 == write(1, &nout, sizeof(nout)))
  84. goto failure;
  85. BN_rshift(N, N, 32); /* N = N/B */
  86. }
  87. /* Write R^2 as little endian array of integers. */
  88. for (i = 0; i < nwords; ++i) {
  89. uint32_t rrout;
  90. BN_mod(rr, RR, B, bn_ctx); /* rr = RR mod B */
  91. rrout = BN_get_word(rr);
  92. if (-1 == write(1, &rrout, sizeof(rrout)))
  93. goto failure;
  94. BN_rshift(RR, RR, 32); /* RR = RR/B */
  95. }
  96. failure:
  97. /* Free BIGNUMs. */
  98. BN_free(Big1);
  99. BN_free(Big2);
  100. BN_free(Big32);
  101. BN_free(BigMinus1);
  102. BN_free(N0inv);
  103. BN_free(R);
  104. BN_free(RRTemp);
  105. BN_free(NnumBits);
  106. BN_free(n);
  107. BN_free(rr);
  108. }
  109. int main(int argc, char* argv[]) {
  110. int cert_mode = 0;
  111. FILE* fp;
  112. X509* cert = NULL;
  113. RSA* pubkey = NULL;
  114. EVP_PKEY* key;
  115. char *progname;
  116. if (argc != 3 || (strcmp(argv[1], "-cert") && strcmp(argv[1], "-pub"))) {
  117. progname = strrchr(argv[0], '/');
  118. if (progname)
  119. progname++;
  120. else
  121. progname = argv[0];
  122. fprintf(stderr, "Usage: %s <-cert | -pub> <file>\n", progname);
  123. return -1;
  124. }
  125. if (!strcmp(argv[1], "-cert"))
  126. cert_mode = 1;
  127. fp = fopen(argv[2], "r");
  128. if (!fp) {
  129. fprintf(stderr, "Couldn't open file %s!\n", argv[2]);
  130. return -1;
  131. }
  132. if (cert_mode) {
  133. /* Read the certificate */
  134. if (!PEM_read_X509(fp, &cert, NULL, NULL)) {
  135. fprintf(stderr, "Couldn't read certificate.\n");
  136. goto fail;
  137. }
  138. /* Get the public key from the certificate. */
  139. key = X509_get_pubkey(cert);
  140. /* Convert to a RSA_style key. */
  141. if (!(pubkey = EVP_PKEY_get1_RSA(key))) {
  142. fprintf(stderr, "Couldn't convert to a RSA style key.\n");
  143. goto fail;
  144. }
  145. } else {
  146. /* Read the pubkey in .PEM format. */
  147. if (!(pubkey = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL))) {
  148. fprintf(stderr, "Couldn't read public key file.\n");
  149. goto fail;
  150. }
  151. }
  152. if (check(pubkey)) {
  153. output(pubkey);
  154. }
  155. fail:
  156. X509_free(cert);
  157. RSA_free(pubkey);
  158. fclose(fp);
  159. return 0;
  160. }