Skip to content

Commit b280eb1

Browse files
committed
x509, ssl, pkcs7: try to parse as DER-encoding first
Methods that take both PEM-encoding and DER-encoding have not been consistent in the order in which encoding to attempt to parse. A DER-encoding may contain a valid PEM block ("\n-----BEGIN ..-----" to "-----END ...-----") embedded within it. Also, the PEM-encoding parser allows arbitrary data around the PEM block and silently skips it. As a result, attempting to parse data in DER-encoding as PEM-encoding first can incorrectly finds the embedded PEM block instead. This commit ensures that DER encoding will always be attempted before PEM encoding. OpenSSL::X509::Certificate is one of the updated classes. With this, the following will always be true: # obj is an OpenSSL::X509::Certificate obj == OpenSSL::X509::Certificate.new(obj.to_der) obj == OpenSSL::X509::Certificate.new(obj.to_pem)
1 parent 964d836 commit b280eb1

File tree

6 files changed

+75
-61
lines changed

6 files changed

+75
-61
lines changed

ext/openssl/ossl_pkcs7.c

+9-11
Original file line numberDiff line numberDiff line change
@@ -330,27 +330,25 @@ ossl_pkcs7_alloc(VALUE klass)
330330
static VALUE
331331
ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self)
332332
{
333-
PKCS7 *p7, *pkcs = DATA_PTR(self);
333+
PKCS7 *p7, *p7_orig = RTYPEDDATA_DATA(self);
334334
BIO *in;
335335
VALUE arg;
336336

337337
if(rb_scan_args(argc, argv, "01", &arg) == 0)
338338
return self;
339339
arg = ossl_to_der_if_possible(arg);
340340
in = ossl_obj2bio(&arg);
341-
p7 = PEM_read_bio_PKCS7(in, &pkcs, NULL, NULL);
341+
p7 = d2i_PKCS7_bio(in, NULL);
342342
if (!p7) {
343-
OSSL_BIO_reset(in);
344-
p7 = d2i_PKCS7_bio(in, &pkcs);
345-
if (!p7) {
346-
BIO_free(in);
347-
PKCS7_free(pkcs);
348-
DATA_PTR(self) = NULL;
349-
ossl_raise(rb_eArgError, "Could not parse the PKCS7");
350-
}
343+
OSSL_BIO_reset(in);
344+
p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
351345
}
352-
DATA_PTR(self) = pkcs;
353346
BIO_free(in);
347+
if (!p7)
348+
ossl_raise(rb_eArgError, "Could not parse the PKCS7");
349+
350+
RTYPEDDATA_DATA(self) = p7;
351+
PKCS7_free(p7_orig);
354352
ossl_pkcs7_set_data(self, Qnil);
355353
ossl_pkcs7_set_err_string(self, Qnil);
356354

ext/openssl/ossl_ssl_session.c

+24-29
Original file line numberDiff line numberDiff line change
@@ -34,43 +34,38 @@ static VALUE ossl_ssl_session_alloc(VALUE klass)
3434
* Creates a new Session object from an instance of SSLSocket or DER/PEM encoded
3535
* String.
3636
*/
37-
static VALUE ossl_ssl_session_initialize(VALUE self, VALUE arg1)
37+
static VALUE
38+
ossl_ssl_session_initialize(VALUE self, VALUE arg1)
3839
{
39-
SSL_SESSION *ctx = NULL;
40-
41-
if (RDATA(self)->data)
42-
ossl_raise(eSSLSession, "SSL Session already initialized");
43-
44-
if (rb_obj_is_instance_of(arg1, cSSLSocket)) {
45-
SSL *ssl;
46-
47-
GetSSL(arg1, ssl);
48-
49-
if ((ctx = SSL_get1_session(ssl)) == NULL)
50-
ossl_raise(eSSLSession, "no session available");
51-
} else {
52-
BIO *in = ossl_obj2bio(&arg1);
40+
SSL_SESSION *ctx;
5341

54-
ctx = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL);
42+
if (RTYPEDDATA_DATA(self))
43+
ossl_raise(eSSLSession, "SSL Session already initialized");
5544

56-
if (!ctx) {
57-
OSSL_BIO_reset(in);
58-
ctx = d2i_SSL_SESSION_bio(in, NULL);
59-
}
45+
if (rb_obj_is_instance_of(arg1, cSSLSocket)) {
46+
SSL *ssl;
6047

61-
BIO_free(in);
48+
GetSSL(arg1, ssl);
6249

63-
if (!ctx)
64-
ossl_raise(rb_eArgError, "unknown type");
65-
}
50+
if ((ctx = SSL_get1_session(ssl)) == NULL)
51+
ossl_raise(eSSLSession, "no session available");
52+
}
53+
else {
54+
BIO *in = ossl_obj2bio(&arg1);
6655

67-
/* should not happen */
68-
if (ctx == NULL)
69-
ossl_raise(eSSLSession, "ctx not set - internal error");
56+
ctx = d2i_SSL_SESSION_bio(in, NULL);
57+
if (!ctx) {
58+
OSSL_BIO_reset(in);
59+
ctx = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL);
60+
}
61+
BIO_free(in);
62+
if (!ctx)
63+
ossl_raise(rb_eArgError, "unknown type");
64+
}
7065

71-
RDATA(self)->data = ctx;
66+
RTYPEDDATA_DATA(self) = ctx;
7267

73-
return self;
68+
return self;
7469
}
7570

7671
static VALUE

ext/openssl/ossl_x509cert.c

+10-7
Original file line numberDiff line numberDiff line change
@@ -115,24 +115,27 @@ static VALUE
115115
ossl_x509_initialize(int argc, VALUE *argv, VALUE self)
116116
{
117117
BIO *in;
118-
X509 *x509, *x = DATA_PTR(self);
118+
X509 *x509, *x509_orig = RTYPEDDATA_DATA(self);
119119
VALUE arg;
120120

121+
rb_check_frozen(self);
121122
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
122123
/* create just empty X509Cert */
123124
return self;
124125
}
125126
arg = ossl_to_der_if_possible(arg);
126127
in = ossl_obj2bio(&arg);
127-
x509 = PEM_read_bio_X509(in, &x, NULL, NULL);
128-
DATA_PTR(self) = x;
128+
x509 = d2i_X509_bio(in, NULL);
129129
if (!x509) {
130-
OSSL_BIO_reset(in);
131-
x509 = d2i_X509_bio(in, &x);
132-
DATA_PTR(self) = x;
130+
OSSL_BIO_reset(in);
131+
x509 = PEM_read_bio_X509(in, NULL, NULL, NULL);
133132
}
134133
BIO_free(in);
135-
if (!x509) ossl_raise(eX509CertError, NULL);
134+
if (!x509)
135+
ossl_raise(eX509CertError, "PEM_read_bio_X509");
136+
137+
RTYPEDDATA_DATA(self) = x509;
138+
X509_free(x509_orig);
136139

137140
return self;
138141
}

ext/openssl/ossl_x509crl.c

+10-7
Original file line numberDiff line numberDiff line change
@@ -93,23 +93,26 @@ static VALUE
9393
ossl_x509crl_initialize(int argc, VALUE *argv, VALUE self)
9494
{
9595
BIO *in;
96-
X509_CRL *crl, *x = DATA_PTR(self);
96+
X509_CRL *crl, *crl_orig = RTYPEDDATA_DATA(self);
9797
VALUE arg;
9898

99+
rb_check_frozen(self);
99100
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
100101
return self;
101102
}
102103
arg = ossl_to_der_if_possible(arg);
103104
in = ossl_obj2bio(&arg);
104-
crl = PEM_read_bio_X509_CRL(in, &x, NULL, NULL);
105-
DATA_PTR(self) = x;
105+
crl = d2i_X509_CRL_bio(in, NULL);
106106
if (!crl) {
107-
OSSL_BIO_reset(in);
108-
crl = d2i_X509_CRL_bio(in, &x);
109-
DATA_PTR(self) = x;
107+
OSSL_BIO_reset(in);
108+
crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL);
110109
}
111110
BIO_free(in);
112-
if (!crl) ossl_raise(eX509CRLError, NULL);
111+
if (!crl)
112+
ossl_raise(eX509CRLError, "PEM_read_bio_X509_CRL");
113+
114+
RTYPEDDATA_DATA(self) = crl;
115+
X509_CRL_free(crl_orig);
113116

114117
return self;
115118
}

ext/openssl/ossl_x509req.c

+10-7
Original file line numberDiff line numberDiff line change
@@ -79,23 +79,26 @@ static VALUE
7979
ossl_x509req_initialize(int argc, VALUE *argv, VALUE self)
8080
{
8181
BIO *in;
82-
X509_REQ *req, *x = DATA_PTR(self);
82+
X509_REQ *req, *req_orig = RTYPEDDATA_DATA(self);
8383
VALUE arg;
8484

85+
rb_check_frozen(self);
8586
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
8687
return self;
8788
}
8889
arg = ossl_to_der_if_possible(arg);
8990
in = ossl_obj2bio(&arg);
90-
req = PEM_read_bio_X509_REQ(in, &x, NULL, NULL);
91-
DATA_PTR(self) = x;
91+
req = d2i_X509_REQ_bio(in, NULL);
9292
if (!req) {
93-
OSSL_BIO_reset(in);
94-
req = d2i_X509_REQ_bio(in, &x);
95-
DATA_PTR(self) = x;
93+
OSSL_BIO_reset(in);
94+
req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL);
9695
}
9796
BIO_free(in);
98-
if (!req) ossl_raise(eX509ReqError, NULL);
97+
if (!req)
98+
ossl_raise(eX509ReqError, "PEM_read_bio_X509_REQ");
99+
100+
RTYPEDDATA_DATA(self) = req;
101+
X509_REQ_free(req_orig);
99102

100103
return self;
101104
}

test/openssl/test_x509cert.rb

+12
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,18 @@ def test_read_from_file
245245
}
246246
end
247247

248+
def test_read_der_then_pem
249+
cert1 = issue_cert(@ca, @rsa2048, 1, [], nil, nil)
250+
exts = [
251+
# A new line before PEM block
252+
["nsComment", "Another certificate:\n" + cert1.to_pem],
253+
]
254+
cert2 = issue_cert(@ca, @rsa2048, 2, exts, nil, nil)
255+
256+
assert_equal cert2, OpenSSL::X509::Certificate.new(cert2.to_der)
257+
assert_equal cert2, OpenSSL::X509::Certificate.new(cert2.to_pem)
258+
end
259+
248260
def test_eq
249261
now = Time.now
250262
cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil,

0 commit comments

Comments
 (0)