1 /* $OpenBSD: x509_info.c,v 1.2 2020/09/18 14:41:04 tb Exp $ */ 2 /* 3 * Copyright (c) 2020 Ingo Schwarze <schwarze@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <err.h> 19 #include <string.h> 20 21 #include <openssl/bio.h> 22 #include <openssl/err.h> 23 #include <openssl/pem.h> 24 #include <openssl/x509.h> 25 26 static const char *const bogus_pem = "\ 27 -----BEGIN BOGUS----- \n\ 28 -----END BOGUS----- \n\ 29 "; 30 31 static const char *const cert_pem = "\ 32 -----BEGIN CERTIFICATE----- \n\ 33 MIIDpTCCAo2gAwIBAgIJAPYm3GvOr5eTMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV \n\ 34 BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMSIwIAYDVQQLDBlGT1IgVEVT \n\ 35 VElORyBQVVJQT1NFUyBPTkxZMSUwIwYDVQQDDBxPcGVuU1NMIFRlc3QgSW50ZXJt \n\ 36 ZWRpYXRlIENBMB4XDTE0MDUyNDE0NDUxMVoXDTI0MDQwMTE0NDUxMVowZDELMAkG \n\ 37 A1UEBhMCVUsxFjAUBgNVBAoMDU9wZW5TU0wgR3JvdXAxIjAgBgNVBAsMGUZPUiBU \n\ 38 RVNUSU5HIFBVUlBPU0VTIE9OTFkxGTAXBgNVBAMMEFRlc3QgQ2xpZW50IENlcnQw \n\ 39 ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0ranbHRLcLVqN+0BzcZpY \n\ 40 +yOLqxzDWT1LD9eW1stC4NzXX9/DCtSIVyN7YIHdGLrIPr64IDdXXaMRzgZ2rOKs \n\ 41 lmHCAiFpO/ja99gGCJRxH0xwQatqAULfJVHeUhs7OEGOZc2nWifjqKvGfNTilP7D \n\ 42 nwi69ipQFq9oS19FmhwVHk2wg7KZGHI1qDyG04UrfCZMRitvS9+UVhPpIPjuiBi2 \n\ 43 x3/FZIpL5gXJvvFK6xHY63oq2asyzBATntBgnP4qJFWWcvRx24wF1PnZabxuVoL2 \n\ 44 bPnQ/KvONDrw3IdqkKhYNTul7jEcu3OlcZIMw+7DiaKJLAzKb/bBF5gm/pwW6As9 \n\ 45 AgMBAAGjTjBMMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgXgMCwGCWCGSAGG \n\ 46 +EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0B \n\ 47 AQUFAAOCAQEAJzA4KTjkjXGSC4He63yX9Br0DneGBzjAwc1H6f72uqnCs8m7jgkE \n\ 48 PQJFdTzQUKh97QPUuayZ2gl8XHagg+iWGy60Kw37gQ0+lumCN2sllvifhHU9R03H \n\ 49 bWtS4kue+yQjMbrzf3zWygMDgwvFOUAIgBpH9qGc+CdNu97INTYd0Mvz51vLlxRn \n\ 50 sC5aBYCWaZFnw3lWYxf9eVFRy9U+DkYFqX0LpmbDtcKP7AZGE6ZwSzaim+Cnoz1u \n\ 51 Cgn+QmpFXgJKMFIZ82iSZISn+JkCCGxctZX1lMvai4Wi8Y0HxW9FTFZ6KBNwwE4B \n\ 52 zjbN/ehBkgLlW/DWfi44DvwUHmuU6QP3cw== \n\ 53 -----END CERTIFICATE----- \n\ 54 "; 55 56 int 57 main(void) 58 { 59 BIO *bp; 60 STACK_OF(X509_INFO) *skin, *skout; 61 X509_INFO *info0, *info1; 62 const char *errdata; 63 unsigned long errcode; 64 int errcount, errflags, num; 65 66 errcount = 0; 67 if ((skin = sk_X509_INFO_new_null()) == NULL) 68 err(1, "sk_X509_INFO_new_null"); 69 70 /* Test with empty input. */ 71 72 if ((bp = BIO_new_mem_buf("", 0)) == NULL) 73 err(1, "BIO_new_mem_buf(empty)"); 74 if ((skout = PEM_X509_INFO_read_bio(bp, skin, NULL, NULL)) == NULL) 75 err(1, "empty input: %s", 76 ERR_error_string(ERR_get_error(), NULL)); 77 if (skout != skin) 78 errx(1, "empty input did not return the same stack"); 79 skout = NULL; 80 if ((num = sk_X509_INFO_num(skin)) != 0) 81 errx(1, "empty input created %d X509_INFO objects", num); 82 BIO_free(bp); 83 84 /* Test with bogus input. */ 85 86 if ((bp = BIO_new_mem_buf(bogus_pem, strlen(bogus_pem))) == NULL) 87 err(1, "BIO_new_mem_buf(bogus_pem)"); 88 if ((skout = PEM_X509_INFO_read_bio(bp, skin, NULL, NULL)) != NULL) 89 errx(1, "success with bogus input on first try"); 90 if ((num = sk_X509_INFO_num(skin)) != 0) 91 errx(1, "bogus input created %d X509_INFO objects", num); 92 if (BIO_reset(bp) != 1) 93 errx(1, "BIO_reset"); 94 95 /* Populate stack and test again with bogus input. */ 96 97 if ((info0 = X509_INFO_new()) == NULL) 98 err(1, "X509_INFO_new"); 99 info0->references = 2; /* X509_INFO_up_ref(3) doesn't exist. */ 100 if (sk_X509_INFO_push(skin, info0) != 1) 101 err(1, "sk_X509_INFO_push"); 102 if ((skout = PEM_X509_INFO_read_bio(bp, skin, NULL, NULL)) != NULL) 103 errx(1, "success with bogus input on second try"); 104 if ((num = sk_X509_INFO_num(skin)) != 1) 105 errx(1, "bogus input changed stack size from 1 to %d", num); 106 if (sk_X509_INFO_value(skin, 0) != info0) 107 errx(1, "bogus input changed stack content"); 108 if (info0->references != 2) { 109 warnx("bogus input changed ref count from 2 to %d", 110 info0->references); 111 info0->references = 2; 112 errcount++; 113 } 114 BIO_free(bp); 115 116 /* Use a real certificate object. */ 117 118 if ((bp = BIO_new_mem_buf(cert_pem, strlen(cert_pem))) == NULL) 119 err(1, "BIO_new_mem_buf(cert_pem)"); 120 if ((skout = PEM_X509_INFO_read_bio(bp, skin, NULL, NULL)) == NULL) { 121 errdata = NULL; 122 errflags = 0; 123 while ((errcode = ERR_get_error_line_data(NULL, NULL, 124 &errdata, &errflags)) != 0) 125 if (errdata != NULL && (errflags & ERR_TXT_STRING)) 126 warnx("%s --- %s", 127 ERR_error_string(errcode, NULL), 128 errdata); 129 else 130 warnx("%s", ERR_error_string(errcode, NULL)); 131 err(1, "real input: parsing failed"); 132 } 133 if (skout != skin) 134 errx(1, "real input did not return the same stack"); 135 skout = NULL; 136 if ((num = sk_X509_INFO_num(skin)) != 2) 137 errx(1, "real input changed stack size from 1 to %d", num); 138 if (sk_X509_INFO_value(skin, 0) != info0) 139 errx(1, "real input changed stack content"); 140 if (info0->references != 2) 141 errx(1, "real input changed ref count from 2 to %d", 142 info0->references); 143 info1 = sk_X509_INFO_pop(skin); 144 if (info1->x509 == NULL) 145 errx(1, "real input did not create a certificate"); 146 X509_INFO_free(info1); 147 info1 = NULL; 148 BIO_free(bp); 149 150 /* Two real certificates followed by bogus input. */ 151 152 if ((bp = BIO_new(BIO_s_mem())) == NULL) 153 err(1, "BIO_new"); 154 if (BIO_puts(bp, cert_pem) != strlen(cert_pem)) 155 err(1, "BIO_puts(cert_pem) first copy"); 156 if (BIO_puts(bp, cert_pem) != strlen(cert_pem)) 157 err(1, "BIO_puts(cert_pem) second copy"); 158 if (BIO_puts(bp, bogus_pem) != strlen(bogus_pem)) 159 err(1, "BIO_puts(bogus_pem)"); 160 if ((skout = PEM_X509_INFO_read_bio(bp, skin, NULL, NULL)) != NULL) 161 errx(1, "success with real + bogus input"); 162 if ((num = sk_X509_INFO_num(skin)) != 1) { 163 warnx("real + bogus input changed stack size from 1 to %d", 164 num); 165 while (sk_X509_INFO_num(skin) > 1) 166 (void)sk_X509_INFO_pop(skin); 167 errcount++; 168 } 169 if (sk_X509_INFO_value(skin, 0) != info0) 170 errx(1, "real + bogus input changed stack content"); 171 if (info0->references != 2) { 172 warnx("real + bogus input changed ref count from 2 to %d", 173 info0->references); 174 errcount++; 175 } 176 BIO_free(bp); 177 info0->references = 1; 178 X509_INFO_free(info0); 179 sk_X509_INFO_free(skin); 180 181 if (errcount > 0) 182 errx(1, "%d errors detected", errcount); 183 return 0; 184 } 185