summaryrefslogtreecommitdiff
path: root/src/regress/lib
diff options
context:
space:
mode:
authorschwarze <>2020-07-23 17:15:35 +0000
committerschwarze <>2020-07-23 17:15:35 +0000
commit006d896f4376dbbbff0a958d5fe8639ab0c070d5 (patch)
treec8fd156c6634db94fcd09f8530f24d6fe60371b3 /src/regress/lib
parentf9151c76d47b4d5c6c4e171b7c4d485a6ff5dd12 (diff)
downloadopenbsd-006d896f4376dbbbff0a958d5fe8639ab0c070d5.tar.gz
openbsd-006d896f4376dbbbff0a958d5fe8639ab0c070d5.tar.bz2
openbsd-006d896f4376dbbbff0a958d5fe8639ab0c070d5.zip
Fix a bug in PEM_X509_INFO_read_bio(3) that is very likely to cause
use-after-free and double-free issues in calling programs. The bug was introduced in SSLeay-0.6.0 released on June 21, 1996 and has been present since OpenBSD 2.4. I found the bug while documenting the function. The bug could bite in two ways that looked quite different from the perspective of the calling code: * If a stack was passed in that already contained some X509_INFO objects and an error occurred, all the objects passed in would be freed, but without removing the freed pointers from the stack, so the calling code would probable continue to access the freed pointers and eventually free them a second time. * If the input BIO contained at least two valid PEM objects followed by at least one PEM object causing an error, at least one freed pointer would be put onto the stack, even though the function would return NULL rather than the stack. But the calling code would still have a pointer to the stack, so it would be likely to access the new bogus pointers sooner or later. Fix all this by remembering the size of the input stack on entry and cutting it back to exactly that size when exiting due to an error, but no further. While here, do some related cleanup: * Garbage collect the automatic variables "error" and "i" which were only used at one single place each. * Use NULL rather than 0 for pointers. I like bugfixes that make the code four lines shorter, reduce the number of variables by one, reduce the number of brace-blocks by one, reduce the number if if-statements by one, and reduce the number of else-clauses by one. Tweaks and OK tb@.
Diffstat (limited to 'src/regress/lib')
-rw-r--r--src/regress/lib/libcrypto/Makefile3
-rw-r--r--src/regress/lib/libcrypto/pem/Makefile8
-rw-r--r--src/regress/lib/libcrypto/pem/x509_info.c184
3 files changed, 194 insertions, 1 deletions
diff --git a/src/regress/lib/libcrypto/Makefile b/src/regress/lib/libcrypto/Makefile
index a5b4cc3855..8d6d40d62e 100644
--- a/src/regress/lib/libcrypto/Makefile
+++ b/src/regress/lib/libcrypto/Makefile
@@ -1,4 +1,4 @@
1# $OpenBSD: Makefile,v 1.38 2020/07/14 18:33:34 jsing Exp $ 1# $OpenBSD: Makefile,v 1.39 2020/07/23 17:15:35 schwarze Exp $
2 2
3SUBDIR += aead 3SUBDIR += aead
4SUBDIR += aeswrap 4SUBDIR += aeswrap
@@ -33,6 +33,7 @@ SUBDIR += init
33SUBDIR += md4 33SUBDIR += md4
34SUBDIR += md5 34SUBDIR += md5
35SUBDIR += pbkdf2 35SUBDIR += pbkdf2
36SUBDIR += pem
36SUBDIR += pkcs7 37SUBDIR += pkcs7
37SUBDIR += poly1305 38SUBDIR += poly1305
38SUBDIR += rand 39SUBDIR += rand
diff --git a/src/regress/lib/libcrypto/pem/Makefile b/src/regress/lib/libcrypto/pem/Makefile
new file mode 100644
index 0000000000..34561e217f
--- /dev/null
+++ b/src/regress/lib/libcrypto/pem/Makefile
@@ -0,0 +1,8 @@
1# $OpenBSD: Makefile,v 1.1 2020/07/23 17:15:35 schwarze Exp $
2
3PROG = x509_info
4LDADD = -lcrypto
5WARNINGS = Yes
6CFLAGS += -Werror
7
8.include <bsd.regress.mk>
diff --git a/src/regress/lib/libcrypto/pem/x509_info.c b/src/regress/lib/libcrypto/pem/x509_info.c
new file mode 100644
index 0000000000..e6b5388a71
--- /dev/null
+++ b/src/regress/lib/libcrypto/pem/x509_info.c
@@ -0,0 +1,184 @@
1/* $OpenBSD: x509_info.c,v 1.1 2020/07/23 17:15:35 schwarze 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
26static const char *const bogus_pem = "\
27-----BEGIN BOGUS----- \n\
28-----END BOGUS----- \n\
29";
30
31static const char *const cert_pem = "\
32-----BEGIN CERTIFICATE----- \n\
33MIIDpTCCAo2gAwIBAgIJAPYm3GvOr5eTMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV \n\
34BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMSIwIAYDVQQLDBlGT1IgVEVT \n\
35VElORyBQVVJQT1NFUyBPTkxZMSUwIwYDVQQDDBxPcGVuU1NMIFRlc3QgSW50ZXJt \n\
36ZWRpYXRlIENBMB4XDTE0MDUyNDE0NDUxMVoXDTI0MDQwMTE0NDUxMVowZDELMAkG \n\
37A1UEBhMCVUsxFjAUBgNVBAoMDU9wZW5TU0wgR3JvdXAxIjAgBgNVBAsMGUZPUiBU \n\
38RVNUSU5HIFBVUlBPU0VTIE9OTFkxGTAXBgNVBAMMEFRlc3QgQ2xpZW50IENlcnQw \n\
39ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0ranbHRLcLVqN+0BzcZpY \n\
40+yOLqxzDWT1LD9eW1stC4NzXX9/DCtSIVyN7YIHdGLrIPr64IDdXXaMRzgZ2rOKs \n\
41lmHCAiFpO/ja99gGCJRxH0xwQatqAULfJVHeUhs7OEGOZc2nWifjqKvGfNTilP7D \n\
42nwi69ipQFq9oS19FmhwVHk2wg7KZGHI1qDyG04UrfCZMRitvS9+UVhPpIPjuiBi2 \n\
43x3/FZIpL5gXJvvFK6xHY63oq2asyzBATntBgnP4qJFWWcvRx24wF1PnZabxuVoL2 \n\
44bPnQ/KvONDrw3IdqkKhYNTul7jEcu3OlcZIMw+7DiaKJLAzKb/bBF5gm/pwW6As9 \n\
45AgMBAAGjTjBMMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgXgMCwGCWCGSAGG \n\
46+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0B \n\
47AQUFAAOCAQEAJzA4KTjkjXGSC4He63yX9Br0DneGBzjAwc1H6f72uqnCs8m7jgkE \n\
48PQJFdTzQUKh97QPUuayZ2gl8XHagg+iWGy60Kw37gQ0+lumCN2sllvifhHU9R03H \n\
49bWtS4kue+yQjMbrzf3zWygMDgwvFOUAIgBpH9qGc+CdNu97INTYd0Mvz51vLlxRn \n\
50sC5aBYCWaZFnw3lWYxf9eVFRy9U+DkYFqX0LpmbDtcKP7AZGE6ZwSzaim+Cnoz1u \n\
51Cgn+QmpFXgJKMFIZ82iSZISn+JkCCGxctZX1lMvai4Wi8Y0HxW9FTFZ6KBNwwE4B \n\
52zjbN/ehBkgLlW/DWfi44DvwUHmuU6QP3cw== \n\
53-----END CERTIFICATE----- \n\
54";
55
56int
57main(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 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}