x509_verify.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
  2. /* SPDX-License-Identifier: Unlicense */
  3. /* load a X.509 certificate chain and verify its validity */
  4. #include <tomcrypt.h>
  5. #include <stdarg.h>
  6. #ifdef LTC_QUIET
  7. static void print_err(const char *fmt, ...)
  8. {
  9. LTC_UNUSED_PARAM(fmt);
  10. }
  11. #define print_stderr(...)
  12. #else
  13. static void print_err(const char *fmt, ...)
  14. {
  15. va_list args;
  16. va_start(args, fmt);
  17. vfprintf(stderr, fmt, args);
  18. va_end(args);
  19. }
  20. #define print_stderr(...) fprintf(stderr, ##__VA_ARGS__)
  21. #endif
  22. #if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 1
  23. #define LTC_DER_PRINT_FLEXI_NO_MAIN
  24. #include "der_print_flexi.c"
  25. static void s_der_print_flexi(const ltc_asn1_list* l)
  26. {
  27. print_stderr("\n\n");
  28. s_der_print_flexi_i(l, 0);
  29. print_stderr("\n\n");
  30. }
  31. #else
  32. static void s_der_print_flexi(const ltc_asn1_list* l)
  33. {
  34. LTC_UNUSED_PARAM(l);
  35. }
  36. #endif
  37. static unsigned long num_certs;
  38. static const ltc_x509_certificate *cert[256] = {0};
  39. static FILE *f;
  40. static void die_(int err, int line)
  41. {
  42. unsigned long n;
  43. print_err("%3d: LTC sez %s\n", line, error_to_string(err));
  44. for (n = num_certs; n --> 0;) {
  45. x509_free(&cert[n]);
  46. }
  47. if (f) fclose(f);
  48. exit(EXIT_FAILURE);
  49. }
  50. #define die(i) do { die_(i, __LINE__); } while(0)
  51. #define DIE(s, ...) do { print_err("%3d: " s "\n", __LINE__, ##__VA_ARGS__); exit(EXIT_FAILURE); } while(0)
  52. #ifndef LTC_ARRAY_SIZE
  53. #define LTC_ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
  54. #endif
  55. int main(int argc, char **argv)
  56. {
  57. const unsigned char zero_cert_buf[sizeof(cert)] = {0};
  58. int err, argn = 1;
  59. unsigned long len, processed, n;
  60. long tell, tot_data = 0;
  61. if ((err = register_all_hashes()) != CRYPT_OK) {
  62. die(err);
  63. }
  64. if ((err = crypt_mp_init("ltm")) != CRYPT_OK) {
  65. die(err);
  66. }
  67. next:
  68. tot_data = processed = num_certs = n = 0;
  69. if (argc > argn) f = fopen(argv[argn], "r");
  70. else f = stdin;
  71. if (f == NULL) DIE("fopen sez no");
  72. if (f != stdin) {
  73. fseek(f, 0, SEEK_END);
  74. tot_data = ftell(f);
  75. fseek(f, 0, SEEK_SET);
  76. tell = 0;
  77. } else {
  78. tell = -1;
  79. }
  80. print_stderr("-=-=-=-=-=-=-\nDecode %s\n=-=-=-=-=-=-=\n", argv[argn]);
  81. while (tell != tot_data) {
  82. err = x509_import_pem_filehandle(f, &cert[n]);
  83. if (err == CRYPT_PK_ASN1_ERROR || err == CRYPT_UNKNOWN_PEM)
  84. continue;
  85. else if (err != CRYPT_OK)
  86. break;
  87. if (cert[n] && cert[n]->asn1)
  88. s_der_print_flexi(cert[n]->asn1);
  89. if (f != stdin) {
  90. tell = ftell(f);
  91. print_stderr("%2lu len: %ld - tot: %ld - processed: %lu (%s)\n", n, tell, tot_data, processed, error_to_string(err));
  92. len = tell - processed;
  93. processed += len;
  94. }
  95. n++;
  96. if (n == LTC_ARRAY_SIZE(cert))
  97. break;
  98. }
  99. num_certs = n;
  100. print_stderr("len: %ld - tot: %ld - processed: %lu (%s)\n", tell, tot_data, processed, error_to_string(err));
  101. if (err && argc > argn) goto check_next;
  102. if (err && err != CRYPT_NOP) die(err);
  103. for (n = 0; n < num_certs; ++n) {
  104. unsigned long m = n + 1 == num_certs ? n : n + 1;
  105. int stat;
  106. if ((err = x509_cert_is_signed_by(cert[n], &cert[m]->tbs_certificate.subject_public_key_info, &stat)) != CRYPT_OK) {
  107. print_err("%3d: LTC sez %s\n", __LINE__, error_to_string(err));
  108. if (m == n) {
  109. print_stderr("Cert is last in chain, but not self-signed.\n");
  110. } else {
  111. break;
  112. }
  113. }
  114. {
  115. const ltc_x509_string *subjects[4];
  116. const ltc_x509_name *subject, *issuer;
  117. int issuer_matches_next_subject = x509_cmp_name(&cert[n]->tbs_certificate.issuer, &cert[m]->tbs_certificate.subject);
  118. subject = &cert[n]->tbs_certificate.subject;
  119. if (n != m) {
  120. issuer = &cert[m]->tbs_certificate.subject;
  121. } else {
  122. issuer = &cert[m]->tbs_certificate.issuer;
  123. }
  124. x509_name_detail_get(subject, LTC_X509_CN, &subjects[0]);
  125. x509_name_detail_get(subject, LTC_X509_O, &subjects[2]);
  126. x509_name_detail_get(issuer, LTC_X509_CN, &subjects[1]);
  127. x509_name_detail_get(issuer, LTC_X509_O, &subjects[3]);
  128. #define X509_STRING_STR(s) (s) ? (s)->str : "NULL"
  129. print_stderr("Cert: %s - %s\nCA: %s - %s\nIssuer matches next subject: %s\nVerify: %s\n",
  130. X509_STRING_STR(subjects[0]), X509_STRING_STR(subjects[2]),
  131. X509_STRING_STR(subjects[1]), X509_STRING_STR(subjects[3]),
  132. issuer_matches_next_subject ? "True" : "False", stat ? "Success" : "Failed");
  133. /* In case of LTC_QUIET this would show up as unused. */
  134. LTC_UNUSED_PARAM(issuer_matches_next_subject);
  135. }
  136. }
  137. check_next:
  138. for (n = num_certs; n --> 0;) {
  139. x509_free(&cert[n]);
  140. }
  141. if (XMEMCMP(cert, zero_cert_buf, sizeof(zero_cert_buf))) {
  142. DIE("cert buf not completely cleaned");
  143. }
  144. if (f != stdin) {
  145. fclose(f);
  146. argn++;
  147. if (argc > argn) {
  148. goto next;
  149. }
  150. }
  151. return 0;
  152. }