openssl 2.2.1 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +33 -45
  3. data/History.md +248 -1
  4. data/README.md +36 -19
  5. data/ext/openssl/extconf.rb +101 -68
  6. data/ext/openssl/openssl_missing.c +0 -66
  7. data/ext/openssl/openssl_missing.h +26 -45
  8. data/ext/openssl/ossl.c +128 -237
  9. data/ext/openssl/ossl.h +31 -12
  10. data/ext/openssl/ossl_asn1.c +26 -13
  11. data/ext/openssl/ossl_bn.c +213 -139
  12. data/ext/openssl/ossl_cipher.c +13 -14
  13. data/ext/openssl/ossl_config.c +412 -41
  14. data/ext/openssl/ossl_config.h +4 -7
  15. data/ext/openssl/ossl_digest.c +10 -10
  16. data/ext/openssl/ossl_engine.c +17 -16
  17. data/ext/openssl/ossl_hmac.c +57 -136
  18. data/ext/openssl/ossl_kdf.c +12 -4
  19. data/ext/openssl/ossl_ns_spki.c +1 -1
  20. data/ext/openssl/ossl_ocsp.c +11 -59
  21. data/ext/openssl/ossl_pkcs12.c +22 -4
  22. data/ext/openssl/ossl_pkcs7.c +45 -62
  23. data/ext/openssl/ossl_pkey.c +1320 -196
  24. data/ext/openssl/ossl_pkey.h +36 -73
  25. data/ext/openssl/ossl_pkey_dh.c +152 -347
  26. data/ext/openssl/ossl_pkey_dsa.c +157 -413
  27. data/ext/openssl/ossl_pkey_ec.c +227 -343
  28. data/ext/openssl/ossl_pkey_rsa.c +159 -491
  29. data/ext/openssl/ossl_provider.c +211 -0
  30. data/ext/openssl/ossl_provider.h +5 -0
  31. data/ext/openssl/ossl_ssl.c +530 -450
  32. data/ext/openssl/ossl_ssl_session.c +29 -30
  33. data/ext/openssl/ossl_ts.c +38 -23
  34. data/ext/openssl/ossl_x509.c +0 -6
  35. data/ext/openssl/ossl_x509attr.c +1 -1
  36. data/ext/openssl/ossl_x509cert.c +168 -12
  37. data/ext/openssl/ossl_x509crl.c +14 -11
  38. data/ext/openssl/ossl_x509ext.c +14 -9
  39. data/ext/openssl/ossl_x509name.c +10 -3
  40. data/ext/openssl/ossl_x509req.c +14 -11
  41. data/ext/openssl/ossl_x509revoked.c +4 -4
  42. data/ext/openssl/ossl_x509store.c +166 -75
  43. data/lib/openssl/buffering.rb +9 -3
  44. data/lib/openssl/digest.rb +1 -5
  45. data/lib/openssl/hmac.rb +65 -0
  46. data/lib/openssl/pkey.rb +429 -0
  47. data/lib/openssl/ssl.rb +22 -17
  48. data/lib/openssl/version.rb +1 -1
  49. data/lib/openssl/x509.rb +22 -0
  50. data/lib/openssl.rb +0 -1
  51. metadata +10 -79
  52. data/ext/openssl/ruby_missing.h +0 -24
  53. data/lib/openssl/config.rb +0 -501
@@ -4,6 +4,7 @@
4
4
 
5
5
  #include "ossl.h"
6
6
 
7
+ #ifndef OPENSSL_NO_SOCK
7
8
  VALUE cSSLSession;
8
9
  static VALUE eSSLSession;
9
10
 
@@ -18,7 +19,7 @@ const rb_data_type_t ossl_ssl_session_type = {
18
19
  {
19
20
  0, ossl_ssl_session_free,
20
21
  },
21
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
22
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
22
23
  };
23
24
 
24
25
  static VALUE ossl_ssl_session_alloc(VALUE klass)
@@ -34,43 +35,38 @@ static VALUE ossl_ssl_session_alloc(VALUE klass)
34
35
  * Creates a new Session object from an instance of SSLSocket or DER/PEM encoded
35
36
  * String.
36
37
  */
37
- static VALUE ossl_ssl_session_initialize(VALUE self, VALUE arg1)
38
+ static VALUE
39
+ ossl_ssl_session_initialize(VALUE self, VALUE arg1)
38
40
  {
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);
41
+ SSL_SESSION *ctx;
53
42
 
54
- ctx = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL);
43
+ if (RTYPEDDATA_DATA(self))
44
+ ossl_raise(eSSLSession, "SSL Session already initialized");
55
45
 
56
- if (!ctx) {
57
- OSSL_BIO_reset(in);
58
- ctx = d2i_SSL_SESSION_bio(in, NULL);
59
- }
46
+ if (rb_obj_is_instance_of(arg1, cSSLSocket)) {
47
+ SSL *ssl;
60
48
 
61
- BIO_free(in);
49
+ GetSSL(arg1, ssl);
62
50
 
63
- if (!ctx)
64
- ossl_raise(rb_eArgError, "unknown type");
65
- }
51
+ if ((ctx = SSL_get1_session(ssl)) == NULL)
52
+ ossl_raise(eSSLSession, "no session available");
53
+ }
54
+ else {
55
+ BIO *in = ossl_obj2bio(&arg1);
66
56
 
67
- /* should not happen */
68
- if (ctx == NULL)
69
- ossl_raise(eSSLSession, "ctx not set - internal error");
57
+ ctx = d2i_SSL_SESSION_bio(in, NULL);
58
+ if (!ctx) {
59
+ OSSL_BIO_reset(in);
60
+ ctx = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL);
61
+ }
62
+ BIO_free(in);
63
+ if (!ctx)
64
+ ossl_raise(rb_eArgError, "unknown type");
65
+ }
70
66
 
71
- RDATA(self)->data = ctx;
67
+ RTYPEDDATA_DATA(self) = ctx;
72
68
 
73
- return self;
69
+ return self;
74
70
  }
75
71
 
76
72
  static VALUE
@@ -304,6 +300,7 @@ static VALUE ossl_ssl_session_to_text(VALUE self)
304
300
  return ossl_membio2str(out);
305
301
  }
306
302
 
303
+ #endif /* !defined(OPENSSL_NO_SOCK) */
307
304
 
308
305
  void Init_ossl_ssl_session(void)
309
306
  {
@@ -312,6 +309,7 @@ void Init_ossl_ssl_session(void)
312
309
  mSSL = rb_define_module_under(mOSSL, "SSL");
313
310
  eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
314
311
  #endif
312
+ #ifndef OPENSSL_NO_SOCK
315
313
  cSSLSession = rb_define_class_under(mSSL, "Session", rb_cObject);
316
314
  eSSLSession = rb_define_class_under(cSSLSession, "SessionError", eOSSLError);
317
315
 
@@ -329,4 +327,5 @@ void Init_ossl_ssl_session(void)
329
327
  rb_define_method(cSSLSession, "to_der", ossl_ssl_session_to_der, 0);
330
328
  rb_define_method(cSSLSession, "to_pem", ossl_ssl_session_to_pem, 0);
331
329
  rb_define_method(cSSLSession, "to_text", ossl_ssl_session_to_text, 0);
330
+ #endif /* !defined(OPENSSL_NO_SOCK) */
332
331
  }
@@ -83,7 +83,7 @@ static const rb_data_type_t ossl_ts_req_type = {
83
83
  {
84
84
  0, ossl_ts_req_free,
85
85
  },
86
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
86
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
87
87
  };
88
88
 
89
89
  static void
@@ -97,7 +97,7 @@ static const rb_data_type_t ossl_ts_resp_type = {
97
97
  {
98
98
  0, ossl_ts_resp_free,
99
99
  },
100
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
100
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
101
101
  };
102
102
 
103
103
  static void
@@ -111,7 +111,7 @@ static const rb_data_type_t ossl_ts_token_info_type = {
111
111
  {
112
112
  0, ossl_ts_token_info_free,
113
113
  },
114
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
114
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
115
115
  };
116
116
 
117
117
  static VALUE
@@ -145,6 +145,12 @@ obj_to_asn1obj(VALUE obj)
145
145
  return a1obj;
146
146
  }
147
147
 
148
+ static VALUE
149
+ obj_to_asn1obj_i(VALUE obj)
150
+ {
151
+ return (VALUE)obj_to_asn1obj(obj);
152
+ }
153
+
148
154
  static VALUE
149
155
  get_asn1obj(ASN1_OBJECT *obj)
150
156
  {
@@ -820,17 +826,14 @@ ossl_ts_resp_verify(int argc, VALUE *argv, VALUE self)
820
826
  X509_up_ref(cert);
821
827
  }
822
828
 
823
- TS_VERIFY_CTS_set_certs(ctx, x509inter);
829
+ TS_VERIFY_CTX_set_certs(ctx, x509inter);
824
830
  TS_VERIFY_CTX_add_flags(ctx, TS_VFY_SIGNATURE);
825
831
  TS_VERIFY_CTX_set_store(ctx, x509st);
826
832
 
827
833
  ok = TS_RESP_verify_response(ctx, resp);
828
-
829
- /* WORKAROUND:
830
- * X509_STORE can count references, but X509_STORE_free() doesn't check
831
- * this. To prevent our X509_STORE from being freed with our
832
- * TS_VERIFY_CTX we set the store to NULL first.
833
- * Fixed in OpenSSL 1.0.2; bff9ce4db38b (master), 5b4b9ce976fc (1.0.2)
834
+ /*
835
+ * TS_VERIFY_CTX_set_store() call above does not increment the reference
836
+ * counter, so it must be unset before TS_VERIFY_CTX_free() is called.
834
837
  */
835
838
  TS_VERIFY_CTX_set_store(ctx, NULL);
836
839
  TS_VERIFY_CTX_free(ctx);
@@ -1091,6 +1094,18 @@ ossl_tsfac_time_cb(struct TS_resp_ctx *ctx, void *data, time_t *sec, long *usec)
1091
1094
  return 1;
1092
1095
  }
1093
1096
 
1097
+ static VALUE
1098
+ ossl_evp_get_digestbyname_i(VALUE arg)
1099
+ {
1100
+ return (VALUE)ossl_evp_get_digestbyname(arg);
1101
+ }
1102
+
1103
+ static VALUE
1104
+ ossl_obj2bio_i(VALUE arg)
1105
+ {
1106
+ return (VALUE)ossl_obj2bio((VALUE *)arg);
1107
+ }
1108
+
1094
1109
  /*
1095
1110
  * Creates a Response with the help of an OpenSSL::PKey, an
1096
1111
  * OpenSSL::X509::Certificate and a Request.
@@ -1159,7 +1174,7 @@ ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
1159
1174
  goto end;
1160
1175
  }
1161
1176
  if (!NIL_P(def_policy_id) && !TS_REQ_get_policy_id(req)) {
1162
- def_policy_id_obj = (ASN1_OBJECT*)rb_protect((VALUE (*)(VALUE))obj_to_asn1obj, (VALUE)def_policy_id, &status);
1177
+ def_policy_id_obj = (ASN1_OBJECT*)rb_protect(obj_to_asn1obj_i, (VALUE)def_policy_id, &status);
1163
1178
  if (status)
1164
1179
  goto end;
1165
1180
  }
@@ -1201,7 +1216,7 @@ ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
1201
1216
 
1202
1217
  for (i = 0; i < RARRAY_LEN(allowed_digests); i++) {
1203
1218
  rbmd = rb_ary_entry(allowed_digests, i);
1204
- md = (const EVP_MD *)rb_protect((VALUE (*)(VALUE))ossl_evp_get_digestbyname, rbmd, &status);
1219
+ md = (const EVP_MD *)rb_protect(ossl_evp_get_digestbyname_i, rbmd, &status);
1205
1220
  if (status)
1206
1221
  goto end;
1207
1222
  TS_RESP_CTX_add_md(ctx, md);
@@ -1212,7 +1227,7 @@ ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
1212
1227
  if (status)
1213
1228
  goto end;
1214
1229
 
1215
- req_bio = (BIO*)rb_protect((VALUE (*)(VALUE))ossl_obj2bio, (VALUE)&str, &status);
1230
+ req_bio = (BIO*)rb_protect(ossl_obj2bio_i, (VALUE)&str, &status);
1216
1231
  if (status)
1217
1232
  goto end;
1218
1233
 
@@ -1236,7 +1251,7 @@ end:
1236
1251
  ASN1_OBJECT_free(def_policy_id_obj);
1237
1252
  TS_RESP_CTX_free(ctx);
1238
1253
  if (err_msg)
1239
- ossl_raise(eTimestampError, err_msg);
1254
+ rb_exc_raise(ossl_make_error(eTimestampError, rb_str_new_cstr(err_msg)));
1240
1255
  if (status)
1241
1256
  rb_jump_tag(status);
1242
1257
  return ret;
@@ -1290,7 +1305,7 @@ Init_ossl_ts(void)
1290
1305
  * ===Create a Response:
1291
1306
  * #Assumes ts.p12 is a PKCS#12-compatible file with a private key
1292
1307
  * #and a certificate that has an extended key usage of 'timeStamping'
1293
- * p12 = OpenSSL::PKCS12.new(File.open('ts.p12', 'rb'), 'pwd')
1308
+ * p12 = OpenSSL::PKCS12.new(File.binread('ts.p12'), 'pwd')
1294
1309
  * md = OpenSSL::Digest.new('SHA1')
1295
1310
  * hash = md.digest(data) #some binary data to be timestamped
1296
1311
  * req = OpenSSL::Timestamp::Request.new
@@ -1305,16 +1320,16 @@ Init_ossl_ts(void)
1305
1320
  *
1306
1321
  * ===Verify a timestamp response:
1307
1322
  * #Assume we have a timestamp token in a file called ts.der
1308
- * ts = OpenSSL::Timestamp::Response.new(File.open('ts.der', 'rb')
1323
+ * ts = OpenSSL::Timestamp::Response.new(File.binread('ts.der'))
1309
1324
  * #Assume we have the Request for this token in a file called req.der
1310
- * req = OpenSSL::Timestamp::Request.new(File.open('req.der', 'rb')
1325
+ * req = OpenSSL::Timestamp::Request.new(File.binread('req.der'))
1311
1326
  * # Assume the associated root CA certificate is contained in a
1312
1327
  * # DER-encoded file named root.cer
1313
- * root = OpenSSL::X509::Certificate.new(File.open('root.cer', 'rb')
1328
+ * root = OpenSSL::X509::Certificate.new(File.binread('root.cer'))
1314
1329
  * # get the necessary intermediate certificates, available in
1315
1330
  * # DER-encoded form in inter1.cer and inter2.cer
1316
- * inter1 = OpenSSL::X509::Certificate.new(File.open('inter1.cer', 'rb')
1317
- * inter2 = OpenSSL::X509::Certificate.new(File.open('inter2.cer', 'rb')
1331
+ * inter1 = OpenSSL::X509::Certificate.new(File.binread('inter1.cer'))
1332
+ * inter2 = OpenSSL::X509::Certificate.new(File.binread('inter2.cer'))
1318
1333
  * ts.verify(req, root, inter1, inter2) -> ts or raises an exception if validation fails
1319
1334
  *
1320
1335
  */
@@ -1447,9 +1462,9 @@ Init_ossl_ts(void)
1447
1462
  * timestamping certificate.
1448
1463
  *
1449
1464
  * req = OpenSSL::Timestamp::Request.new(raw_bytes)
1450
- * p12 = OpenSSL::PKCS12.new(File.open('ts.p12', 'rb'), 'pwd')
1451
- * inter1 = OpenSSL::X509::Certificate.new(File.open('inter1.cer', 'rb')
1452
- * inter2 = OpenSSL::X509::Certificate.new(File.open('inter2.cer', 'rb')
1465
+ * p12 = OpenSSL::PKCS12.new(File.binread('ts.p12'), 'pwd')
1466
+ * inter1 = OpenSSL::X509::Certificate.new(File.binread('inter1.cer'))
1467
+ * inter2 = OpenSSL::X509::Certificate.new(File.binread('inter2.cer'))
1453
1468
  * fac = OpenSSL::Timestamp::Factory.new
1454
1469
  * fac.gen_time = Time.now
1455
1470
  * fac.serial_number = 1
@@ -115,11 +115,9 @@ Init_ossl_x509(void)
115
115
  DefX509Const(V_ERR_SUITE_B_LOS_NOT_ALLOWED);
116
116
  DefX509Const(V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256);
117
117
  #endif
118
- #if defined(X509_V_ERR_HOSTNAME_MISMATCH)
119
118
  DefX509Const(V_ERR_HOSTNAME_MISMATCH);
120
119
  DefX509Const(V_ERR_EMAIL_MISMATCH);
121
120
  DefX509Const(V_ERR_IP_ADDRESS_MISMATCH);
122
- #endif
123
121
  #if defined(X509_V_ERR_DANE_NO_MATCH)
124
122
  DefX509Const(V_ERR_DANE_NO_MATCH);
125
123
  #endif
@@ -187,12 +185,10 @@ Init_ossl_x509(void)
187
185
  /* Set by Store#flags= and StoreContext#flags=. Enables checking of the
188
186
  * signature of the root self-signed CA. */
189
187
  DefX509Const(V_FLAG_CHECK_SS_SIGNATURE);
190
- #if defined(X509_V_FLAG_TRUSTED_FIRST)
191
188
  /* Set by Store#flags= and StoreContext#flags=. When constructing a
192
189
  * certificate chain, search the Store first for the issuer certificate.
193
190
  * Enabled by default in OpenSSL >= 1.1.0. */
194
191
  DefX509Const(V_FLAG_TRUSTED_FIRST);
195
- #endif
196
192
  #if defined(X509_V_FLAG_SUITEB_128_LOS_ONLY)
197
193
  /* Set by Store#flags= and StoreContext#flags=.
198
194
  * Enables Suite B 128 bit only mode. */
@@ -208,11 +204,9 @@ Init_ossl_x509(void)
208
204
  * Enables Suite B 128 bit mode allowing 192 bit algorithms. */
209
205
  DefX509Const(V_FLAG_SUITEB_128_LOS);
210
206
  #endif
211
- #if defined(X509_V_FLAG_PARTIAL_CHAIN)
212
207
  /* Set by Store#flags= and StoreContext#flags=.
213
208
  * Allows partial chains if at least one certificate is in trusted store. */
214
209
  DefX509Const(V_FLAG_PARTIAL_CHAIN);
215
- #endif
216
210
  #if defined(X509_V_FLAG_NO_ALT_CHAINS)
217
211
  /* Set by Store#flags= and StoreContext#flags=. Suppresses searching for
218
212
  * a alternative chain. No effect in OpenSSL >= 1.1.0. */
@@ -41,7 +41,7 @@ static const rb_data_type_t ossl_x509attr_type = {
41
41
  {
42
42
  0, ossl_x509attr_free,
43
43
  },
44
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
44
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
45
45
  };
46
46
 
47
47
  /*
@@ -41,7 +41,7 @@ static const rb_data_type_t ossl_x509_type = {
41
41
  {
42
42
  0, ossl_x509_free,
43
43
  },
44
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
44
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
45
45
  };
46
46
 
47
47
  /*
@@ -115,24 +115,27 @@ static VALUE
115
115
  ossl_x509_initialize(int argc, VALUE *argv, VALUE self)
116
116
  {
117
117
  BIO *in;
118
- X509 *x509, *x = DATA_PTR(self);
118
+ X509 *x509, *x509_orig = RTYPEDDATA_DATA(self);
119
119
  VALUE arg;
120
120
 
121
+ rb_check_frozen(self);
121
122
  if (rb_scan_args(argc, argv, "01", &arg) == 0) {
122
123
  /* create just empty X509Cert */
123
124
  return self;
124
125
  }
125
126
  arg = ossl_to_der_if_possible(arg);
126
127
  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);
129
129
  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);
133
132
  }
134
133
  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);
136
139
 
137
140
  return self;
138
141
  }
@@ -639,12 +642,12 @@ ossl_x509_set_extensions(VALUE self, VALUE ary)
639
642
  OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
640
643
  }
641
644
  GetX509(self, x509);
642
- while ((ext = X509_delete_ext(x509, 0)))
643
- X509_EXTENSION_free(ext);
645
+ for (i = X509_get_ext_count(x509); i > 0; i--)
646
+ X509_EXTENSION_free(X509_delete_ext(x509, 0));
644
647
  for (i=0; i<RARRAY_LEN(ary); i++) {
645
648
  ext = GetX509ExtPtr(RARRAY_AREF(ary, i));
646
649
  if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext */
647
- ossl_raise(eX509CertError, NULL);
650
+ ossl_raise(eX509CertError, "X509_add_ext");
648
651
  }
649
652
  }
650
653
 
@@ -704,6 +707,157 @@ ossl_x509_eq(VALUE self, VALUE other)
704
707
  return !X509_cmp(a, b) ? Qtrue : Qfalse;
705
708
  }
706
709
 
710
+ struct load_chained_certificates_arguments {
711
+ VALUE certificates;
712
+ X509 *certificate;
713
+ };
714
+
715
+ static VALUE
716
+ load_chained_certificates_append_push(VALUE _arguments) {
717
+ struct load_chained_certificates_arguments *arguments = (struct load_chained_certificates_arguments*)_arguments;
718
+
719
+ if (arguments->certificates == Qnil) {
720
+ arguments->certificates = rb_ary_new();
721
+ }
722
+
723
+ rb_ary_push(arguments->certificates, ossl_x509_new(arguments->certificate));
724
+
725
+ return Qnil;
726
+ }
727
+
728
+ static VALUE
729
+ load_chained_certificate_append_ensure(VALUE _arguments) {
730
+ struct load_chained_certificates_arguments *arguments = (struct load_chained_certificates_arguments*)_arguments;
731
+
732
+ X509_free(arguments->certificate);
733
+
734
+ return Qnil;
735
+ }
736
+
737
+ inline static VALUE
738
+ load_chained_certificates_append(VALUE certificates, X509 *certificate) {
739
+ struct load_chained_certificates_arguments arguments;
740
+ arguments.certificates = certificates;
741
+ arguments.certificate = certificate;
742
+
743
+ rb_ensure(load_chained_certificates_append_push, (VALUE)&arguments, load_chained_certificate_append_ensure, (VALUE)&arguments);
744
+
745
+ return arguments.certificates;
746
+ }
747
+
748
+ static VALUE
749
+ load_chained_certificates_PEM(BIO *in) {
750
+ VALUE certificates = Qnil;
751
+ X509 *certificate = PEM_read_bio_X509(in, NULL, NULL, NULL);
752
+
753
+ /* If we cannot read even one certificate: */
754
+ if (certificate == NULL) {
755
+ /* If we cannot read one certificate because we could not read the PEM encoding: */
756
+ if (ERR_GET_REASON(ERR_peek_last_error()) == PEM_R_NO_START_LINE) {
757
+ ossl_clear_error();
758
+ }
759
+
760
+ if (ERR_peek_last_error())
761
+ ossl_raise(eX509CertError, NULL);
762
+ else
763
+ return Qnil;
764
+ }
765
+
766
+ certificates = load_chained_certificates_append(Qnil, certificate);
767
+
768
+ while ((certificate = PEM_read_bio_X509(in, NULL, NULL, NULL))) {
769
+ load_chained_certificates_append(certificates, certificate);
770
+ }
771
+
772
+ /* We tried to read one more certificate but could not read start line: */
773
+ if (ERR_GET_REASON(ERR_peek_last_error()) == PEM_R_NO_START_LINE) {
774
+ /* This is not an error, it means we are finished: */
775
+ ossl_clear_error();
776
+
777
+ return certificates;
778
+ }
779
+
780
+ /* Alternatively, if we reached the end of the file and there was no error: */
781
+ if (BIO_eof(in) && !ERR_peek_last_error()) {
782
+ return certificates;
783
+ } else {
784
+ /* Otherwise, we tried to read a certificate but failed somewhere: */
785
+ ossl_raise(eX509CertError, NULL);
786
+ }
787
+ }
788
+
789
+ static VALUE
790
+ load_chained_certificates_DER(BIO *in) {
791
+ X509 *certificate = d2i_X509_bio(in, NULL);
792
+
793
+ /* If we cannot read one certificate: */
794
+ if (certificate == NULL) {
795
+ /* Ignore error. We could not load. */
796
+ ossl_clear_error();
797
+
798
+ return Qnil;
799
+ }
800
+
801
+ return load_chained_certificates_append(Qnil, certificate);
802
+ }
803
+
804
+ static VALUE
805
+ load_chained_certificates(VALUE _io) {
806
+ BIO *in = (BIO*)_io;
807
+ VALUE certificates = Qnil;
808
+
809
+ /*
810
+ DER is a binary format and it may contain octets within it that look like
811
+ PEM encoded certificates. So we need to check DER first.
812
+ */
813
+ certificates = load_chained_certificates_DER(in);
814
+
815
+ if (certificates != Qnil)
816
+ return certificates;
817
+
818
+ OSSL_BIO_reset(in);
819
+
820
+ certificates = load_chained_certificates_PEM(in);
821
+
822
+ if (certificates != Qnil)
823
+ return certificates;
824
+
825
+ /* Otherwise we couldn't read the output correctly so fail: */
826
+ ossl_raise(eX509CertError, "Could not detect format of certificate data!");
827
+ }
828
+
829
+ static VALUE
830
+ load_chained_certificates_ensure(VALUE _io) {
831
+ BIO *in = (BIO*)_io;
832
+
833
+ BIO_free(in);
834
+
835
+ return Qnil;
836
+ }
837
+
838
+ /*
839
+ * call-seq:
840
+ * OpenSSL::X509::Certificate.load(string) -> [certs...]
841
+ * OpenSSL::X509::Certificate.load(file) -> [certs...]
842
+ *
843
+ * Read the chained certificates from the given input. Supports both PEM
844
+ * and DER encoded certificates.
845
+ *
846
+ * PEM is a text format and supports more than one certificate.
847
+ *
848
+ * DER is a binary format and only supports one certificate.
849
+ *
850
+ * If the file is empty, or contains only unrelated data, an
851
+ * +OpenSSL::X509::CertificateError+ exception will be raised.
852
+ */
853
+ static VALUE
854
+ ossl_x509_load(VALUE klass, VALUE buffer)
855
+ {
856
+ BIO *in = ossl_obj2bio(&buffer);
857
+
858
+ return rb_ensure(load_chained_certificates, (VALUE)in, load_chained_certificates_ensure, (VALUE)in);
859
+ }
860
+
707
861
  /*
708
862
  * INIT
709
863
  */
@@ -730,7 +884,7 @@ Init_ossl_x509cert(void)
730
884
  * Certificate is capable of handling DER-encoded certificates and
731
885
  * certificates encoded in OpenSSL's PEM format.
732
886
  *
733
- * raw = File.read "cert.cer" # DER- or PEM-encoded
887
+ * raw = File.binread "cert.cer" # DER- or PEM-encoded
734
888
  * certificate = OpenSSL::X509::Certificate.new raw
735
889
  *
736
890
  * === Saving a certificate to a file
@@ -812,6 +966,8 @@ Init_ossl_x509cert(void)
812
966
  */
813
967
  cX509Cert = rb_define_class_under(mX509, "Certificate", rb_cObject);
814
968
 
969
+ rb_define_singleton_method(cX509Cert, "load", ossl_x509_load, 1);
970
+
815
971
  rb_define_alloc_func(cX509Cert, ossl_x509_alloc);
816
972
  rb_define_method(cX509Cert, "initialize", ossl_x509_initialize, -1);
817
973
  rb_define_method(cX509Cert, "initialize_copy", ossl_x509_copy, 1);
@@ -41,7 +41,7 @@ static const rb_data_type_t ossl_x509crl_type = {
41
41
  {
42
42
  0, ossl_x509crl_free,
43
43
  },
44
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
44
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
45
45
  };
46
46
 
47
47
  /*
@@ -93,23 +93,26 @@ static VALUE
93
93
  ossl_x509crl_initialize(int argc, VALUE *argv, VALUE self)
94
94
  {
95
95
  BIO *in;
96
- X509_CRL *crl, *x = DATA_PTR(self);
96
+ X509_CRL *crl, *crl_orig = RTYPEDDATA_DATA(self);
97
97
  VALUE arg;
98
98
 
99
+ rb_check_frozen(self);
99
100
  if (rb_scan_args(argc, argv, "01", &arg) == 0) {
100
101
  return self;
101
102
  }
102
103
  arg = ossl_to_der_if_possible(arg);
103
104
  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);
106
106
  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);
110
109
  }
111
110
  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);
113
116
 
114
117
  return self;
115
118
  }
@@ -471,12 +474,12 @@ ossl_x509crl_set_extensions(VALUE self, VALUE ary)
471
474
  OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
472
475
  }
473
476
  GetX509CRL(self, crl);
474
- while ((ext = X509_CRL_delete_ext(crl, 0)))
475
- X509_EXTENSION_free(ext);
477
+ for (i = X509_CRL_get_ext_count(crl); i > 0; i--)
478
+ X509_EXTENSION_free(X509_CRL_delete_ext(crl, 0));
476
479
  for (i=0; i<RARRAY_LEN(ary); i++) {
477
480
  ext = GetX509ExtPtr(RARRAY_AREF(ary, i)); /* NO NEED TO DUP */
478
481
  if (!X509_CRL_add_ext(crl, ext, -1)) {
479
- ossl_raise(eX509CRLError, NULL);
482
+ ossl_raise(eX509CRLError, "X509_CRL_add_ext");
480
483
  }
481
484
  }
482
485
 
@@ -55,7 +55,7 @@ static const rb_data_type_t ossl_x509ext_type = {
55
55
  {
56
56
  0, ossl_x509ext_free,
57
57
  },
58
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
58
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
59
59
  };
60
60
 
61
61
  /*
@@ -108,7 +108,7 @@ static const rb_data_type_t ossl_x509extfactory_type = {
108
108
  {
109
109
  0, ossl_x509extfactory_free,
110
110
  },
111
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
111
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
112
112
  };
113
113
 
114
114
  static VALUE
@@ -209,15 +209,16 @@ ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self)
209
209
  int nid;
210
210
  VALUE rconf;
211
211
  CONF *conf;
212
+ const char *oid_cstr = NULL;
212
213
 
213
214
  rb_scan_args(argc, argv, "21", &oid, &value, &critical);
214
- StringValueCStr(oid);
215
215
  StringValue(value);
216
216
  if(NIL_P(critical)) critical = Qfalse;
217
217
 
218
- nid = OBJ_ln2nid(RSTRING_PTR(oid));
219
- if(!nid) nid = OBJ_sn2nid(RSTRING_PTR(oid));
220
- if(!nid) ossl_raise(eX509ExtError, "unknown OID `%"PRIsVALUE"'", oid);
218
+ oid_cstr = StringValueCStr(oid);
219
+ nid = OBJ_ln2nid(oid_cstr);
220
+ if (nid != NID_undef)
221
+ oid_cstr = OBJ_nid2sn(nid);
221
222
 
222
223
  valstr = rb_str_new2(RTEST(critical) ? "critical," : "");
223
224
  rb_str_append(valstr, value);
@@ -226,11 +227,15 @@ ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self)
226
227
  GetX509ExtFactory(self, ctx);
227
228
  obj = NewX509Ext(cX509Ext);
228
229
  rconf = rb_iv_get(self, "@config");
229
- conf = NIL_P(rconf) ? NULL : DupConfigPtr(rconf);
230
+ conf = NIL_P(rconf) ? NULL : GetConfig(rconf);
230
231
  X509V3_set_nconf(ctx, conf);
231
- ext = X509V3_EXT_nconf_nid(conf, ctx, nid, RSTRING_PTR(valstr));
232
+
233
+ #if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_IS_LIBRESSL
234
+ ext = X509V3_EXT_nconf(conf, ctx, oid_cstr, RSTRING_PTR(valstr));
235
+ #else
236
+ ext = X509V3_EXT_nconf(conf, ctx, (char *)oid_cstr, RSTRING_PTR(valstr));
237
+ #endif
232
238
  X509V3_set_ctx_nodb(ctx);
233
- NCONF_free(conf);
234
239
  if (!ext){
235
240
  ossl_raise(eX509ExtError, "%"PRIsVALUE" = %"PRIsVALUE, oid, valstr);
236
241
  }