openssl 2.1.0.beta1 → 2.1.0.beta2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of openssl might be problematic. Click here for more details.

@@ -3,6 +3,9 @@
3
3
  * Copyright (C) 2007, 2017 Ruby/OpenSSL Project Authors
4
4
  */
5
5
  #include "ossl.h"
6
+ #if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
7
+ # include <openssl/kdf.h>
8
+ #endif
6
9
 
7
10
  static VALUE mKDF, eKDF;
8
11
 
@@ -138,6 +141,97 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
138
141
  }
139
142
  #endif
140
143
 
144
+ #if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
145
+ /*
146
+ * call-seq:
147
+ * KDF.hkdf(ikm, salt:, info:, length:, hash:) -> String
148
+ *
149
+ * HMAC-based Extract-and-Expand Key Derivation Function (HKDF) as specified in
150
+ * {RFC 5869}[https://tools.ietf.org/html/rfc5869].
151
+ *
152
+ * New in OpenSSL 1.1.0.
153
+ *
154
+ * === Parameters
155
+ * _ikm_::
156
+ * The input keying material.
157
+ * _salt_::
158
+ * The salt.
159
+ * _info_::
160
+ * The context and application specific information.
161
+ * _length_::
162
+ * The output length in octets. Must be <= <tt>255 * HashLen</tt>, where
163
+ * HashLen is the length of the hash function output in octets.
164
+ * _hash_::
165
+ * The hash function.
166
+ */
167
+ static VALUE
168
+ kdf_hkdf(int argc, VALUE *argv, VALUE self)
169
+ {
170
+ VALUE ikm, salt, info, opts, kwargs[4], str;
171
+ static ID kwargs_ids[4];
172
+ int saltlen, ikmlen, infolen;
173
+ size_t len;
174
+ const EVP_MD *md;
175
+ EVP_PKEY_CTX *pctx;
176
+
177
+ if (!kwargs_ids[0]) {
178
+ kwargs_ids[0] = rb_intern_const("salt");
179
+ kwargs_ids[1] = rb_intern_const("info");
180
+ kwargs_ids[2] = rb_intern_const("length");
181
+ kwargs_ids[3] = rb_intern_const("hash");
182
+ }
183
+ rb_scan_args(argc, argv, "1:", &ikm, &opts);
184
+ rb_get_kwargs(opts, kwargs_ids, 4, 0, kwargs);
185
+
186
+ StringValue(ikm);
187
+ ikmlen = RSTRING_LENINT(ikm);
188
+ salt = StringValue(kwargs[0]);
189
+ saltlen = RSTRING_LENINT(salt);
190
+ info = StringValue(kwargs[1]);
191
+ infolen = RSTRING_LENINT(info);
192
+ len = (size_t)NUM2LONG(kwargs[2]);
193
+ if (len > LONG_MAX)
194
+ rb_raise(rb_eArgError, "length must be non-negative");
195
+ md = ossl_evp_get_digestbyname(kwargs[3]);
196
+
197
+ str = rb_str_new(NULL, (long)len);
198
+ pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
199
+ if (!pctx)
200
+ ossl_raise(eKDF, "EVP_PKEY_CTX_new_id");
201
+ if (EVP_PKEY_derive_init(pctx) <= 0) {
202
+ EVP_PKEY_CTX_free(pctx);
203
+ ossl_raise(eKDF, "EVP_PKEY_derive_init");
204
+ }
205
+ if (EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0) {
206
+ EVP_PKEY_CTX_free(pctx);
207
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_md");
208
+ }
209
+ if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, (unsigned char *)RSTRING_PTR(salt),
210
+ saltlen) <= 0) {
211
+ EVP_PKEY_CTX_free(pctx);
212
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_salt");
213
+ }
214
+ if (EVP_PKEY_CTX_set1_hkdf_key(pctx, (unsigned char *)RSTRING_PTR(ikm),
215
+ ikmlen) <= 0) {
216
+ EVP_PKEY_CTX_free(pctx);
217
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_key");
218
+ }
219
+ if (EVP_PKEY_CTX_add1_hkdf_info(pctx, (unsigned char *)RSTRING_PTR(info),
220
+ infolen) <= 0) {
221
+ EVP_PKEY_CTX_free(pctx);
222
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_info");
223
+ }
224
+ if (EVP_PKEY_derive(pctx, (unsigned char *)RSTRING_PTR(str), &len) <= 0) {
225
+ EVP_PKEY_CTX_free(pctx);
226
+ ossl_raise(eKDF, "EVP_PKEY_derive");
227
+ }
228
+ rb_str_set_len(str, (long)len);
229
+ EVP_PKEY_CTX_free(pctx);
230
+
231
+ return str;
232
+ }
233
+ #endif
234
+
141
235
  void
142
236
  Init_ossl_kdf(void)
143
237
  {
@@ -162,6 +256,7 @@ Init_ossl_kdf(void)
162
256
  * * PKCS #5 PBKDF2 (Password-Based Key Derivation Function 2) in
163
257
  * combination with HMAC
164
258
  * * scrypt
259
+ * * HKDF
165
260
  *
166
261
  * == Examples
167
262
  * === Generating a 128 bit key for a Cipher (e.g. AES)
@@ -218,4 +313,7 @@ Init_ossl_kdf(void)
218
313
  #if defined(HAVE_EVP_PBE_SCRYPT)
219
314
  rb_define_module_function(mKDF, "scrypt", kdf_scrypt, -1);
220
315
  #endif
316
+ #if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
317
+ rb_define_module_function(mKDF, "hkdf", kdf_hkdf, -1);
318
+ #endif
221
319
  }
@@ -208,12 +208,13 @@ static VALUE
208
208
  ossl_spki_set_public_key(VALUE self, VALUE key)
209
209
  {
210
210
  NETSCAPE_SPKI *spki;
211
+ EVP_PKEY *pkey;
211
212
 
212
213
  GetSPKI(self, spki);
213
- if (!NETSCAPE_SPKI_set_pubkey(spki, GetPKeyPtr(key))) { /* NO NEED TO DUP */
214
- ossl_raise(eSPKIError, NULL);
215
- }
216
-
214
+ pkey = GetPKeyPtr(key);
215
+ ossl_pkey_check_public_key(pkey);
216
+ if (!NETSCAPE_SPKI_set_pubkey(spki, pkey))
217
+ ossl_raise(eSPKIError, "NETSCAPE_SPKI_set_pubkey");
217
218
  return key;
218
219
  }
219
220
 
@@ -307,17 +308,20 @@ static VALUE
307
308
  ossl_spki_verify(VALUE self, VALUE key)
308
309
  {
309
310
  NETSCAPE_SPKI *spki;
311
+ EVP_PKEY *pkey;
310
312
 
311
313
  GetSPKI(self, spki);
312
- switch (NETSCAPE_SPKI_verify(spki, GetPKeyPtr(key))) { /* NO NEED TO DUP */
313
- case 0:
314
+ pkey = GetPKeyPtr(key);
315
+ ossl_pkey_check_public_key(pkey);
316
+ switch (NETSCAPE_SPKI_verify(spki, pkey)) {
317
+ case 0:
318
+ ossl_clear_error();
314
319
  return Qfalse;
315
- case 1:
320
+ case 1:
316
321
  return Qtrue;
317
- default:
318
- ossl_raise(eSPKIError, NULL);
322
+ default:
323
+ ossl_raise(eSPKIError, "NETSCAPE_SPKI_verify");
319
324
  }
320
- return Qnil; /* dummy */
321
325
  }
322
326
 
323
327
  /* Document-class: OpenSSL::Netscape::SPKI
@@ -163,8 +163,8 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
163
163
  return ossl_pkey_new(pkey);
164
164
  }
165
165
 
166
- static void
167
- pkey_check_public_key(EVP_PKEY *pkey)
166
+ void
167
+ ossl_pkey_check_public_key(const EVP_PKEY *pkey)
168
168
  {
169
169
  void *ptr;
170
170
  const BIGNUM *n, *e, *pubkey;
@@ -172,7 +172,8 @@ pkey_check_public_key(EVP_PKEY *pkey)
172
172
  if (EVP_PKEY_missing_parameters(pkey))
173
173
  ossl_raise(ePKeyError, "parameters missing");
174
174
 
175
- ptr = EVP_PKEY_get0(pkey);
175
+ /* OpenSSL < 1.1.0 takes non-const pointer */
176
+ ptr = EVP_PKEY_get0((EVP_PKEY *)pkey);
176
177
  switch (EVP_PKEY_base_id(pkey)) {
177
178
  case EVP_PKEY_RSA:
178
179
  RSA_get0_key(ptr, &n, &e, NULL);
@@ -352,7 +353,7 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
352
353
  int siglen, result;
353
354
 
354
355
  GetPKey(self, pkey);
355
- pkey_check_public_key(pkey);
356
+ ossl_pkey_check_public_key(pkey);
356
357
  md = ossl_evp_get_digestbyname(digest);
357
358
  StringValue(sig);
358
359
  siglen = RSTRING_LENINT(sig);
@@ -44,6 +44,7 @@ int ossl_generate_cb_2(int p, int n, BN_GENCB *cb);
44
44
  void ossl_generate_cb_stop(void *ptr);
45
45
 
46
46
  VALUE ossl_pkey_new(EVP_PKEY *);
47
+ void ossl_pkey_check_public_key(const EVP_PKEY *);
47
48
  EVP_PKEY *GetPKeyPtr(VALUE);
48
49
  EVP_PKEY *DupPKeyPtr(VALUE);
49
50
  EVP_PKEY *GetPrivPKeyPtr(VALUE);
@@ -536,6 +536,196 @@ ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self)
536
536
  return str;
537
537
  }
538
538
 
539
+ /*
540
+ * call-seq:
541
+ * rsa.sign_pss(digest, data, salt_length:, mgf1_hash:) -> String
542
+ *
543
+ * Signs _data_ using the Probabilistic Signature Scheme (RSA-PSS) and returns
544
+ * the calculated signature.
545
+ *
546
+ * RSAError will be raised if an error occurs.
547
+ *
548
+ * See #verify_pss for the verification operation.
549
+ *
550
+ * === Parameters
551
+ * _digest_::
552
+ * A String containing the message digest algorithm name.
553
+ * _data_::
554
+ * A String. The data to be signed.
555
+ * _salt_length_::
556
+ * The length in octets of the salt. Two special values are reserved:
557
+ * +:digest+ means the digest length, and +:max+ means the maximum possible
558
+ * length for the combination of the private key and the selected message
559
+ * digest algorithm.
560
+ * _mgf1_hash_::
561
+ * The hash algorithm used in MGF1 (the currently supported mask generation
562
+ * function (MGF)).
563
+ *
564
+ * === Example
565
+ * data = "Sign me!"
566
+ * pkey = OpenSSL::PKey::RSA.new(2048)
567
+ * signature = pkey.sign_pss("SHA256", data, salt_length: :max, mgf1_hash: "SHA256")
568
+ * pub_key = pkey.public_key
569
+ * puts pub_key.verify_pss("SHA256", signature, data,
570
+ * salt_length: :auto, mgf1_hash: "SHA256") # => true
571
+ */
572
+ static VALUE
573
+ ossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self)
574
+ {
575
+ VALUE digest, data, options, kwargs[2], signature;
576
+ static ID kwargs_ids[2];
577
+ EVP_PKEY *pkey;
578
+ EVP_PKEY_CTX *pkey_ctx;
579
+ const EVP_MD *md, *mgf1md;
580
+ EVP_MD_CTX *md_ctx;
581
+ size_t buf_len;
582
+ int salt_len;
583
+
584
+ if (!kwargs_ids[0]) {
585
+ kwargs_ids[0] = rb_intern_const("salt_length");
586
+ kwargs_ids[1] = rb_intern_const("mgf1_hash");
587
+ }
588
+ rb_scan_args(argc, argv, "2:", &digest, &data, &options);
589
+ rb_get_kwargs(options, kwargs_ids, 2, 0, kwargs);
590
+ if (kwargs[0] == ID2SYM(rb_intern("max")))
591
+ salt_len = -2; /* RSA_PSS_SALTLEN_MAX_SIGN */
592
+ else if (kwargs[0] == ID2SYM(rb_intern("digest")))
593
+ salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */
594
+ else
595
+ salt_len = NUM2INT(kwargs[0]);
596
+ mgf1md = ossl_evp_get_digestbyname(kwargs[1]);
597
+
598
+ pkey = GetPrivPKeyPtr(self);
599
+ buf_len = EVP_PKEY_size(pkey);
600
+ md = ossl_evp_get_digestbyname(digest);
601
+ StringValue(data);
602
+ signature = rb_str_new(NULL, (long)buf_len);
603
+
604
+ md_ctx = EVP_MD_CTX_new();
605
+ if (!md_ctx)
606
+ goto err;
607
+
608
+ if (EVP_DigestSignInit(md_ctx, &pkey_ctx, md, NULL, pkey) != 1)
609
+ goto err;
610
+
611
+ if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1)
612
+ goto err;
613
+
614
+ if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, salt_len) != 1)
615
+ goto err;
616
+
617
+ if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1md) != 1)
618
+ goto err;
619
+
620
+ if (EVP_DigestSignUpdate(md_ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1)
621
+ goto err;
622
+
623
+ if (EVP_DigestSignFinal(md_ctx, (unsigned char *)RSTRING_PTR(signature), &buf_len) != 1)
624
+ goto err;
625
+
626
+ rb_str_set_len(signature, (long)buf_len);
627
+
628
+ EVP_MD_CTX_free(md_ctx);
629
+ return signature;
630
+
631
+ err:
632
+ EVP_MD_CTX_free(md_ctx);
633
+ ossl_raise(eRSAError, NULL);
634
+ }
635
+
636
+ /*
637
+ * call-seq:
638
+ * rsa.verify_pss(digest, signature, data, salt_length:, mgf1_hash:) -> true | false
639
+ *
640
+ * Verifies _data_ using the Probabilistic Signature Scheme (RSA-PSS).
641
+ *
642
+ * The return value is +true+ if the signature is valid, +false+ otherwise.
643
+ * RSAError will be raised if an error occurs.
644
+ *
645
+ * See #sign_pss for the signing operation and an example code.
646
+ *
647
+ * === Parameters
648
+ * _digest_::
649
+ * A String containing the message digest algorithm name.
650
+ * _data_::
651
+ * A String. The data to be signed.
652
+ * _salt_length_::
653
+ * The length in octets of the salt. Two special values are reserved:
654
+ * +:digest+ means the digest length, and +:auto+ means automatically
655
+ * determining the length based on the signature.
656
+ * _mgf1_hash_::
657
+ * The hash algorithm used in MGF1.
658
+ */
659
+ static VALUE
660
+ ossl_rsa_verify_pss(int argc, VALUE *argv, VALUE self)
661
+ {
662
+ VALUE digest, signature, data, options, kwargs[2];
663
+ static ID kwargs_ids[2];
664
+ EVP_PKEY *pkey;
665
+ EVP_PKEY_CTX *pkey_ctx;
666
+ const EVP_MD *md, *mgf1md;
667
+ EVP_MD_CTX *md_ctx;
668
+ int result, salt_len;
669
+
670
+ if (!kwargs_ids[0]) {
671
+ kwargs_ids[0] = rb_intern_const("salt_length");
672
+ kwargs_ids[1] = rb_intern_const("mgf1_hash");
673
+ }
674
+ rb_scan_args(argc, argv, "3:", &digest, &signature, &data, &options);
675
+ rb_get_kwargs(options, kwargs_ids, 2, 0, kwargs);
676
+ if (kwargs[0] == ID2SYM(rb_intern("auto")))
677
+ salt_len = -2; /* RSA_PSS_SALTLEN_AUTO */
678
+ else if (kwargs[0] == ID2SYM(rb_intern("digest")))
679
+ salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */
680
+ else
681
+ salt_len = NUM2INT(kwargs[0]);
682
+ mgf1md = ossl_evp_get_digestbyname(kwargs[1]);
683
+
684
+ GetPKey(self, pkey);
685
+ md = ossl_evp_get_digestbyname(digest);
686
+ StringValue(signature);
687
+ StringValue(data);
688
+
689
+ md_ctx = EVP_MD_CTX_new();
690
+ if (!md_ctx)
691
+ goto err;
692
+
693
+ if (EVP_DigestVerifyInit(md_ctx, &pkey_ctx, md, NULL, pkey) != 1)
694
+ goto err;
695
+
696
+ if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1)
697
+ goto err;
698
+
699
+ if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, salt_len) != 1)
700
+ goto err;
701
+
702
+ if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1md) != 1)
703
+ goto err;
704
+
705
+ if (EVP_DigestVerifyUpdate(md_ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1)
706
+ goto err;
707
+
708
+ result = EVP_DigestVerifyFinal(md_ctx,
709
+ (unsigned char *)RSTRING_PTR(signature),
710
+ RSTRING_LEN(signature));
711
+
712
+ switch (result) {
713
+ case 0:
714
+ ossl_clear_error();
715
+ EVP_MD_CTX_free(md_ctx);
716
+ return Qfalse;
717
+ case 1:
718
+ EVP_MD_CTX_free(md_ctx);
719
+ return Qtrue;
720
+ default:
721
+ goto err;
722
+ }
723
+
724
+ err:
725
+ EVP_MD_CTX_free(md_ctx);
726
+ ossl_raise(eRSAError, NULL);
727
+ }
728
+
539
729
  /*
540
730
  * call-seq:
541
731
  * rsa.params => hash
@@ -731,6 +921,8 @@ Init_ossl_rsa(void)
731
921
  rb_define_method(cRSA, "public_decrypt", ossl_rsa_public_decrypt, -1);
732
922
  rb_define_method(cRSA, "private_encrypt", ossl_rsa_private_encrypt, -1);
733
923
  rb_define_method(cRSA, "private_decrypt", ossl_rsa_private_decrypt, -1);
924
+ rb_define_method(cRSA, "sign_pss", ossl_rsa_sign_pss, -1);
925
+ rb_define_method(cRSA, "verify_pss", ossl_rsa_verify_pss, -1);
734
926
 
735
927
  DEF_OSSL_PKEY_BN(cRSA, rsa, n);
736
928
  DEF_OSSL_PKEY_BN(cRSA, rsa, e);
@@ -32,7 +32,7 @@ VALUE cSSLSocket;
32
32
  static VALUE eSSLErrorWaitReadable;
33
33
  static VALUE eSSLErrorWaitWritable;
34
34
 
35
- static ID ID_callback_state, id_tmp_dh_callback, id_tmp_ecdh_callback,
35
+ static ID id_call, ID_callback_state, id_tmp_dh_callback, id_tmp_ecdh_callback,
36
36
  id_npn_protocols_encoded;
37
37
  static VALUE sym_exception, sym_wait_readable, sym_wait_writable;
38
38
 
@@ -205,7 +205,7 @@ ossl_call_client_cert_cb(VALUE obj)
205
205
  if (NIL_P(cb))
206
206
  return Qnil;
207
207
 
208
- ary = rb_funcall(cb, rb_intern("call"), 1, obj);
208
+ ary = rb_funcallv(cb, id_call, 1, &obj);
209
209
  Check_Type(ary, T_ARRAY);
210
210
  GetX509CertPtr(cert = rb_ary_entry(ary, 0));
211
211
  GetPrivPKeyPtr(key = rb_ary_entry(ary, 1));
@@ -248,8 +248,8 @@ ossl_call_tmp_dh_callback(struct tmp_dh_callback_args *args)
248
248
  cb = rb_funcall(args->ssl_obj, args->id, 0);
249
249
  if (NIL_P(cb))
250
250
  return NULL;
251
- dh = rb_funcall(cb, rb_intern("call"), 3,
252
- args->ssl_obj, INT2NUM(args->is_export), INT2NUM(args->keylength));
251
+ dh = rb_funcall(cb, id_call, 3, args->ssl_obj, INT2NUM(args->is_export),
252
+ INT2NUM(args->keylength));
253
253
  pkey = GetPKeyPtr(dh);
254
254
  if (EVP_PKEY_base_id(pkey) != args->type)
255
255
  return NULL;
@@ -374,12 +374,12 @@ ossl_call_session_get_cb(VALUE ary)
374
374
  cb = rb_funcall(ssl_obj, rb_intern("session_get_cb"), 0);
375
375
  if (NIL_P(cb)) return Qnil;
376
376
 
377
- return rb_funcall(cb, rb_intern("call"), 1, ary);
377
+ return rb_funcallv(cb, id_call, 1, &ary);
378
378
  }
379
379
 
380
380
  /* this method is currently only called for servers (in OpenSSL <= 0.9.8e) */
381
381
  static SSL_SESSION *
382
- #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
382
+ #if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
383
383
  ossl_sslctx_session_get_cb(SSL *ssl, const unsigned char *buf, int len, int *copy)
384
384
  #else
385
385
  ossl_sslctx_session_get_cb(SSL *ssl, unsigned char *buf, int len, int *copy)
@@ -420,7 +420,7 @@ ossl_call_session_new_cb(VALUE ary)
420
420
  cb = rb_funcall(ssl_obj, rb_intern("session_new_cb"), 0);
421
421
  if (NIL_P(cb)) return Qnil;
422
422
 
423
- return rb_funcall(cb, rb_intern("call"), 1, ary);
423
+ return rb_funcallv(cb, id_call, 1, &ary);
424
424
  }
425
425
 
426
426
  /* return 1 normal. return 0 removes the session */
@@ -467,7 +467,7 @@ ossl_call_session_remove_cb(VALUE ary)
467
467
  cb = rb_attr_get(sslctx_obj, id_i_session_remove_cb);
468
468
  if (NIL_P(cb)) return Qnil;
469
469
 
470
- return rb_funcall(cb, rb_intern("call"), 1, ary);
470
+ return rb_funcallv(cb, id_call, 1, &ary);
471
471
  }
472
472
 
473
473
  static void
@@ -533,7 +533,7 @@ ossl_call_servername_cb(VALUE ary)
533
533
  cb = rb_attr_get(sslctx_obj, id_i_servername_cb);
534
534
  if (NIL_P(cb)) return Qnil;
535
535
 
536
- ret_obj = rb_funcall(cb, rb_intern("call"), 1, ary);
536
+ ret_obj = rb_funcallv(cb, id_call, 1, &ary);
537
537
  if (rb_obj_is_kind_of(ret_obj, cSSLContext)) {
538
538
  SSL *ssl;
539
539
  SSL_CTX *ctx2;
@@ -585,7 +585,7 @@ ssl_renegotiation_cb(const SSL *ssl)
585
585
  cb = rb_attr_get(sslctx_obj, id_i_renegotiation_cb);
586
586
  if (NIL_P(cb)) return;
587
587
 
588
- (void) rb_funcall(cb, rb_intern("call"), 1, ssl_obj);
588
+ rb_funcallv(cb, id_call, 1, &ssl_obj);
589
589
  }
590
590
 
591
591
  #if !defined(OPENSSL_NO_NEXTPROTONEG) || \
@@ -635,7 +635,7 @@ npn_select_cb_common_i(VALUE tmp)
635
635
  in += l;
636
636
  }
637
637
 
638
- selected = rb_funcall(args->cb, rb_intern("call"), 1, protocols);
638
+ selected = rb_funcallv(args->cb, id_call, 1, &protocols);
639
639
  StringValue(selected);
640
640
  len = RSTRING_LEN(selected);
641
641
  if (len < 1 || len >= 256) {
@@ -1193,6 +1193,134 @@ ossl_sslctx_set_security_level(VALUE self, VALUE value)
1193
1193
  return value;
1194
1194
  }
1195
1195
 
1196
+ #ifdef SSL_MODE_SEND_FALLBACK_SCSV
1197
+ /*
1198
+ * call-seq:
1199
+ * ctx.enable_fallback_scsv() => nil
1200
+ *
1201
+ * Activate TLS_FALLBACK_SCSV for this context.
1202
+ * See RFC 7507.
1203
+ */
1204
+ static VALUE
1205
+ ossl_sslctx_enable_fallback_scsv(VALUE self)
1206
+ {
1207
+ SSL_CTX *ctx;
1208
+
1209
+ GetSSLCTX(self, ctx);
1210
+ SSL_CTX_set_mode(ctx, SSL_MODE_SEND_FALLBACK_SCSV);
1211
+
1212
+ return Qnil;
1213
+ }
1214
+ #endif
1215
+
1216
+ /*
1217
+ * call-seq:
1218
+ * ctx.add_certificate(certiticate, pkey [, extra_certs]) -> self
1219
+ *
1220
+ * Adds a certificate to the context. _pkey_ must be a corresponding private
1221
+ * key with _certificate_.
1222
+ *
1223
+ * Multiple certificates with different public key type can be added by
1224
+ * repeated calls of this method, and OpenSSL will choose the most appropriate
1225
+ * certificate during the handshake.
1226
+ *
1227
+ * #cert=, #key=, and #extra_chain_cert= are old accessor methods for setting
1228
+ * certificate and internally call this method.
1229
+ *
1230
+ * === Parameters
1231
+ * _certificate_::
1232
+ * A certificate. An instance of OpenSSL::X509::Certificate.
1233
+ * _pkey_::
1234
+ * The private key for _certificate_. An instance of OpenSSL::PKey::PKey.
1235
+ * _extra_certs_::
1236
+ * Optional. An array of OpenSSL::X509::Certificate. When sending a
1237
+ * certificate chain, the certificates specified by this are sent following
1238
+ * _certificate_, in the order in the array.
1239
+ *
1240
+ * === Example
1241
+ * rsa_cert = OpenSSL::X509::Certificate.new(...)
1242
+ * rsa_pkey = OpenSSL::PKey.read(...)
1243
+ * ca_intermediate_cert = OpenSSL::X509::Certificate.new(...)
1244
+ * ctx.add_certificate(rsa_cert, rsa_pkey, [ca_intermediate_cert])
1245
+ *
1246
+ * ecdsa_cert = ...
1247
+ * ecdsa_pkey = ...
1248
+ * another_ca_cert = ...
1249
+ * ctx.add_certificate(ecdsa_cert, ecdsa_pkey, [another_ca_cert])
1250
+ *
1251
+ * === Note
1252
+ * OpenSSL before the version 1.0.2 could handle only one extra chain across
1253
+ * all key types. Calling this method discards the chain set previously.
1254
+ */
1255
+ static VALUE
1256
+ ossl_sslctx_add_certificate(int argc, VALUE *argv, VALUE self)
1257
+ {
1258
+ VALUE cert, key, extra_chain_ary;
1259
+ SSL_CTX *ctx;
1260
+ X509 *x509;
1261
+ STACK_OF(X509) *extra_chain = NULL;
1262
+ EVP_PKEY *pkey, *pub_pkey;
1263
+
1264
+ GetSSLCTX(self, ctx);
1265
+ rb_scan_args(argc, argv, "21", &cert, &key, &extra_chain_ary);
1266
+ rb_check_frozen(self);
1267
+ x509 = GetX509CertPtr(cert);
1268
+ pkey = GetPrivPKeyPtr(key);
1269
+
1270
+ /*
1271
+ * The reference counter is bumped, and decremented immediately.
1272
+ * X509_get0_pubkey() is only available in OpenSSL >= 1.1.0.
1273
+ */
1274
+ pub_pkey = X509_get_pubkey(x509);
1275
+ EVP_PKEY_free(pub_pkey);
1276
+ if (!pub_pkey)
1277
+ rb_raise(rb_eArgError, "certificate does not contain public key");
1278
+ if (EVP_PKEY_cmp(pub_pkey, pkey) != 1)
1279
+ rb_raise(rb_eArgError, "public key mismatch");
1280
+
1281
+ if (argc >= 3)
1282
+ extra_chain = ossl_x509_ary2sk(extra_chain_ary);
1283
+
1284
+ if (!SSL_CTX_use_certificate(ctx, x509)) {
1285
+ sk_X509_pop_free(extra_chain, X509_free);
1286
+ ossl_raise(eSSLError, "SSL_CTX_use_certificate");
1287
+ }
1288
+ if (!SSL_CTX_use_PrivateKey(ctx, pkey)) {
1289
+ sk_X509_pop_free(extra_chain, X509_free);
1290
+ ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey");
1291
+ }
1292
+
1293
+ if (extra_chain) {
1294
+ #if OPENSSL_VERSION_NUMBER >= 0x10002000 && !defined(LIBRESSL_VERSION_NUMBER)
1295
+ if (!SSL_CTX_set0_chain(ctx, extra_chain)) {
1296
+ sk_X509_pop_free(extra_chain, X509_free);
1297
+ ossl_raise(eSSLError, "SSL_CTX_set0_chain");
1298
+ }
1299
+ #else
1300
+ STACK_OF(X509) *orig_extra_chain;
1301
+ X509 *x509_tmp;
1302
+
1303
+ /* First, clear the existing chain */
1304
+ SSL_CTX_get_extra_chain_certs(ctx, &orig_extra_chain);
1305
+ if (orig_extra_chain && sk_X509_num(orig_extra_chain)) {
1306
+ rb_warning("SSL_CTX_set0_chain() is not available; " \
1307
+ "clearing previously set certificate chain");
1308
+ SSL_CTX_clear_extra_chain_certs(ctx);
1309
+ }
1310
+ while ((x509_tmp = sk_X509_shift(extra_chain))) {
1311
+ /* Transfers ownership */
1312
+ if (!SSL_CTX_add_extra_chain_cert(ctx, x509_tmp)) {
1313
+ X509_free(x509_tmp);
1314
+ sk_X509_pop_free(extra_chain, X509_free);
1315
+ ossl_raise(eSSLError, "SSL_CTX_add_extra_chain_cert");
1316
+ }
1317
+ }
1318
+ sk_X509_free(extra_chain);
1319
+ #endif
1320
+ }
1321
+ return self;
1322
+ }
1323
+
1196
1324
  /*
1197
1325
  * call-seq:
1198
1326
  * ctx.session_add(session) -> true | false
@@ -1694,20 +1822,26 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
1694
1822
  }
1695
1823
 
1696
1824
  ilen = NUM2INT(len);
1697
- if(NIL_P(str)) str = rb_str_new(0, ilen);
1698
- else{
1699
- StringValue(str);
1700
- rb_str_modify(str);
1701
- rb_str_resize(str, ilen);
1825
+ if (NIL_P(str))
1826
+ str = rb_str_new(0, ilen);
1827
+ else {
1828
+ StringValue(str);
1829
+ if (RSTRING_LEN(str) >= ilen)
1830
+ rb_str_modify(str);
1831
+ else
1832
+ rb_str_modify_expand(str, ilen - RSTRING_LEN(str));
1702
1833
  }
1703
- if(ilen == 0) return str;
1834
+ OBJ_TAINT(str);
1835
+ rb_str_set_len(str, 0);
1836
+ if (ilen == 0)
1837
+ return str;
1704
1838
 
1705
1839
  GetSSL(self, ssl);
1706
1840
  io = rb_attr_get(self, id_i_io);
1707
1841
  GetOpenFile(io, fptr);
1708
1842
  if (ssl_started(ssl)) {
1709
1843
  for (;;){
1710
- nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LENINT(str));
1844
+ nread = SSL_read(ssl, RSTRING_PTR(str), ilen);
1711
1845
  switch(ssl_get_error(ssl, nread)){
1712
1846
  case SSL_ERROR_NONE:
1713
1847
  goto end;
@@ -1757,8 +1891,6 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
1757
1891
 
1758
1892
  end:
1759
1893
  rb_str_set_len(str, nread);
1760
- OBJ_TAINT(str);
1761
-
1762
1894
  return str;
1763
1895
  }
1764
1896
 
@@ -2257,6 +2389,7 @@ Init_ossl_ssl(void)
2257
2389
  rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
2258
2390
  #endif
2259
2391
 
2392
+ id_call = rb_intern("call");
2260
2393
  ID_callback_state = rb_intern("callback_state");
2261
2394
 
2262
2395
  ossl_ssl_ex_vcb_idx = SSL_get_ex_new_index(0, (void *)"ossl_ssl_ex_vcb_idx", 0, 0, 0);
@@ -2320,11 +2453,17 @@ Init_ossl_ssl(void)
2320
2453
 
2321
2454
  /*
2322
2455
  * Context certificate
2456
+ *
2457
+ * The _cert_, _key_, and _extra_chain_cert_ attributes are deprecated.
2458
+ * It is recommended to use #add_certificate instead.
2323
2459
  */
2324
2460
  rb_attr(cSSLContext, rb_intern("cert"), 1, 1, Qfalse);
2325
2461
 
2326
2462
  /*
2327
2463
  * Context private key
2464
+ *
2465
+ * The _cert_, _key_, and _extra_chain_cert_ attributes are deprecated.
2466
+ * It is recommended to use #add_certificate instead.
2328
2467
  */
2329
2468
  rb_attr(cSSLContext, rb_intern("key"), 1, 1, Qfalse);
2330
2469
 
@@ -2398,6 +2537,9 @@ Init_ossl_ssl(void)
2398
2537
  /*
2399
2538
  * An Array of extra X509 certificates to be added to the certificate
2400
2539
  * chain.
2540
+ *
2541
+ * The _cert_, _key_, and _extra_chain_cert_ attributes are deprecated.
2542
+ * It is recommended to use #add_certificate instead.
2401
2543
  */
2402
2544
  rb_attr(cSSLContext, rb_intern("extra_chain_cert"), 1, 1, Qfalse);
2403
2545
 
@@ -2453,6 +2595,10 @@ Init_ossl_ssl(void)
2453
2595
  * A callback invoked when a session is removed from the internal cache.
2454
2596
  *
2455
2597
  * The callback is invoked with an SSLContext and a Session.
2598
+ *
2599
+ * IMPORTANT NOTE: It is currently not possible to use this safely in a
2600
+ * multi-threaded application. The callback is called inside a global lock
2601
+ * and it can randomly cause deadlock on Ruby thread switching.
2456
2602
  */
2457
2603
  rb_attr(cSSLContext, rb_intern("session_remove_cb"), 1, 1, Qfalse);
2458
2604
 
@@ -2553,6 +2699,10 @@ Init_ossl_ssl(void)
2553
2699
  rb_define_method(cSSLContext, "ecdh_curves=", ossl_sslctx_set_ecdh_curves, 1);
2554
2700
  rb_define_method(cSSLContext, "security_level", ossl_sslctx_get_security_level, 0);
2555
2701
  rb_define_method(cSSLContext, "security_level=", ossl_sslctx_set_security_level, 1);
2702
+ #ifdef SSL_MODE_SEND_FALLBACK_SCSV
2703
+ rb_define_method(cSSLContext, "enable_fallback_scsv", ossl_sslctx_enable_fallback_scsv, 0);
2704
+ #endif
2705
+ rb_define_method(cSSLContext, "add_certificate", ossl_sslctx_add_certificate, -1);
2556
2706
 
2557
2707
  rb_define_method(cSSLContext, "setup", ossl_sslctx_setup, 0);
2558
2708
  rb_define_alias(cSSLContext, "freeze", "setup");