1 /* 2 * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * https://www.openssl.org/source/license.html 8 * or in the file LICENSE in the source distribution. 9 */ 10 11 #include <stdio.h> 12 #include <string.h> 13 #include <errno.h> 14 15 #include <openssl/x509.h> 16 #include <openssl/pem.h> 17 #include <openssl/conf.h> 18 #include <openssl/err.h> 19 #include "testutil.h" 20 21 static int test_certs(int num) 22 { 23 int c; 24 char *name = 0; 25 char *header = 0; 26 unsigned char *data = 0; 27 long len; 28 typedef X509 *(*d2i_X509_t)(X509 **, const unsigned char **, long); 29 typedef int (*i2d_X509_t)(const X509 *, unsigned char **); 30 int err = 0; 31 BIO *fp = BIO_new_file(test_get_argument(num), "r"); 32 33 if (!TEST_ptr(fp)) 34 return 0; 35 36 for (c = 0; !err && PEM_read_bio(fp, &name, &header, &data, &len); ++c) { 37 const int trusted = (strcmp(name, PEM_STRING_X509_TRUSTED) == 0); 38 d2i_X509_t d2i = trusted ? d2i_X509_AUX : d2i_X509; 39 i2d_X509_t i2d = trusted ? i2d_X509_AUX : i2d_X509; 40 X509 *cert = NULL; 41 X509 *reuse = NULL; 42 const unsigned char *p = data; 43 unsigned char *buf = NULL; 44 unsigned char *bufp; 45 long enclen; 46 47 if (!trusted 48 && strcmp(name, PEM_STRING_X509) != 0 49 && strcmp(name, PEM_STRING_X509_OLD) != 0) { 50 TEST_error("unexpected PEM object: %s", name); 51 err = 1; 52 goto next; 53 } 54 cert = d2i(NULL, &p, len); 55 56 if (cert == NULL || (p - data) != len) { 57 TEST_error("error parsing input %s", name); 58 err = 1; 59 goto next; 60 } 61 62 /* Test traditional 2-pass encoding into caller allocated buffer */ 63 enclen = i2d(cert, NULL); 64 if (len != enclen) { 65 TEST_error("encoded length %ld of %s != input length %ld", 66 enclen, name, len); 67 err = 1; 68 goto next; 69 } 70 if ((buf = bufp = OPENSSL_malloc(len)) == NULL) { 71 TEST_perror("malloc"); 72 err = 1; 73 goto next; 74 } 75 enclen = i2d(cert, &bufp); 76 if (len != enclen) { 77 TEST_error("encoded length %ld of %s != input length %ld", 78 enclen, name, len); 79 err = 1; 80 goto next; 81 } 82 enclen = (long) (bufp - buf); 83 if (enclen != len) { 84 TEST_error("unexpected buffer position after encoding %s", name); 85 err = 1; 86 goto next; 87 } 88 if (memcmp(buf, data, len) != 0) { 89 TEST_error("encoded content of %s does not match input", name); 90 err = 1; 91 goto next; 92 } 93 p = buf; 94 reuse = d2i(NULL, &p, enclen); 95 if (reuse == NULL) { 96 TEST_error("second d2i call failed for %s", name); 97 err = 1; 98 goto next; 99 } 100 err = X509_cmp(reuse, cert); 101 if (err != 0) { 102 TEST_error("X509_cmp for %s resulted in %d", name, err); 103 err = 1; 104 goto next; 105 } 106 OPENSSL_free(buf); 107 buf = NULL; 108 109 /* Test 1-pass encoding into library allocated buffer */ 110 enclen = i2d(cert, &buf); 111 if (len != enclen) { 112 TEST_error("encoded length %ld of %s != input length %ld", 113 enclen, name, len); 114 err = 1; 115 goto next; 116 } 117 if (memcmp(buf, data, len) != 0) { 118 TEST_error("encoded content of %s does not match input", name); 119 err = 1; 120 goto next; 121 } 122 123 if (trusted) { 124 /* Encode just the cert and compare with initial encoding */ 125 OPENSSL_free(buf); 126 buf = NULL; 127 128 /* Test 1-pass encoding into library allocated buffer */ 129 enclen = i2d(cert, &buf); 130 if (enclen > len) { 131 TEST_error("encoded length %ld of %s > input length %ld", 132 enclen, name, len); 133 err = 1; 134 goto next; 135 } 136 if (memcmp(buf, data, enclen) != 0) { 137 TEST_error("encoded cert content does not match input"); 138 err = 1; 139 goto next; 140 } 141 } 142 143 /* 144 * If any of these were null, PEM_read() would have failed. 145 */ 146 next: 147 X509_free(cert); 148 X509_free(reuse); 149 OPENSSL_free(buf); 150 OPENSSL_free(name); 151 OPENSSL_free(header); 152 OPENSSL_free(data); 153 } 154 BIO_free(fp); 155 156 if (ERR_GET_REASON(ERR_peek_last_error()) == PEM_R_NO_START_LINE) { 157 /* Reached end of PEM file */ 158 if (c > 0) { 159 ERR_clear_error(); 160 return 1; 161 } 162 } 163 164 /* Some other PEM read error */ 165 return 0; 166 } 167 168 OPT_TEST_DECLARE_USAGE("certfile...\n") 169 170 int setup_tests(void) 171 { 172 size_t n; 173 174 if (!test_skip_common_options()) { 175 TEST_error("Error parsing test options\n"); 176 return 0; 177 } 178 179 n = test_get_argument_count(); 180 if (n == 0) 181 return 0; 182 183 ADD_ALL_TESTS(test_certs, (int)n); 184 return 1; 185 } 186