openssl 2.2.2 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +33 -45
  3. data/History.md +232 -1
  4. data/README.md +36 -19
  5. data/ext/openssl/extconf.rb +100 -67
  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
  }