rubysl-openssl 2.10 → 2.11

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 (55) hide show
  1. checksums.yaml +5 -5
  2. data/ext/rubysl/openssl/deprecation.rb +7 -3
  3. data/ext/rubysl/openssl/extconf.rb +148 -103
  4. data/ext/rubysl/openssl/openssl_missing.c +94 -275
  5. data/ext/rubysl/openssl/openssl_missing.h +167 -98
  6. data/ext/rubysl/openssl/ossl.c +266 -212
  7. data/ext/rubysl/openssl/ossl.h +27 -89
  8. data/ext/rubysl/openssl/ossl_asn1.c +157 -221
  9. data/ext/rubysl/openssl/ossl_asn1.h +11 -3
  10. data/ext/rubysl/openssl/ossl_bio.c +10 -40
  11. data/ext/rubysl/openssl/ossl_bio.h +1 -2
  12. data/ext/rubysl/openssl/ossl_bn.c +144 -100
  13. data/ext/rubysl/openssl/ossl_bn.h +3 -1
  14. data/ext/rubysl/openssl/ossl_cipher.c +270 -195
  15. data/ext/rubysl/openssl/ossl_config.c +7 -1
  16. data/ext/rubysl/openssl/ossl_config.h +0 -1
  17. data/ext/rubysl/openssl/ossl_digest.c +40 -29
  18. data/ext/rubysl/openssl/ossl_engine.c +23 -62
  19. data/ext/rubysl/openssl/ossl_hmac.c +82 -55
  20. data/ext/rubysl/openssl/ossl_ns_spki.c +22 -22
  21. data/ext/rubysl/openssl/ossl_ocsp.c +894 -144
  22. data/ext/rubysl/openssl/ossl_ocsp.h +1 -1
  23. data/ext/rubysl/openssl/ossl_pkcs12.c +47 -19
  24. data/ext/rubysl/openssl/ossl_pkcs5.c +7 -15
  25. data/ext/rubysl/openssl/ossl_pkcs7.c +38 -15
  26. data/ext/rubysl/openssl/ossl_pkey.c +151 -99
  27. data/ext/rubysl/openssl/ossl_pkey.h +123 -29
  28. data/ext/rubysl/openssl/ossl_pkey_dh.c +143 -92
  29. data/ext/rubysl/openssl/ossl_pkey_dsa.c +149 -104
  30. data/ext/rubysl/openssl/ossl_pkey_ec.c +646 -524
  31. data/ext/rubysl/openssl/ossl_pkey_rsa.c +180 -121
  32. data/ext/rubysl/openssl/ossl_rand.c +25 -21
  33. data/ext/rubysl/openssl/ossl_ssl.c +795 -413
  34. data/ext/rubysl/openssl/ossl_ssl.h +3 -0
  35. data/ext/rubysl/openssl/ossl_ssl_session.c +83 -77
  36. data/ext/rubysl/openssl/ossl_version.h +1 -1
  37. data/ext/rubysl/openssl/ossl_x509.c +92 -8
  38. data/ext/rubysl/openssl/ossl_x509.h +14 -5
  39. data/ext/rubysl/openssl/ossl_x509attr.c +77 -41
  40. data/ext/rubysl/openssl/ossl_x509cert.c +45 -46
  41. data/ext/rubysl/openssl/ossl_x509crl.c +51 -57
  42. data/ext/rubysl/openssl/ossl_x509ext.c +39 -33
  43. data/ext/rubysl/openssl/ossl_x509name.c +68 -45
  44. data/ext/rubysl/openssl/ossl_x509req.c +32 -38
  45. data/ext/rubysl/openssl/ossl_x509revoked.c +43 -9
  46. data/ext/rubysl/openssl/ossl_x509store.c +309 -104
  47. data/ext/rubysl/openssl/ruby_missing.h +8 -6
  48. data/lib/openssl/buffering.rb +11 -5
  49. data/lib/openssl/cipher.rb +23 -15
  50. data/lib/openssl/digest.rb +7 -10
  51. data/lib/openssl/pkey.rb +15 -8
  52. data/lib/openssl/ssl.rb +81 -105
  53. data/lib/rubysl/openssl.rb +1 -4
  54. data/lib/rubysl/openssl/version.rb +1 -1
  55. metadata +3 -4
@@ -15,8 +15,10 @@ extern VALUE eBNError;
15
15
 
16
16
  extern BN_CTX *ossl_bn_ctx;
17
17
 
18
+ #define GetBNPtr(obj) ossl_bn_value_ptr(&(obj))
19
+
18
20
  VALUE ossl_bn_new(const BIGNUM *);
19
- BIGNUM *GetBNPtr(VALUE);
21
+ BIGNUM *ossl_bn_value_ptr(volatile VALUE *);
20
22
  void Init_ossl_bn(void);
21
23
 
22
24
 
@@ -11,17 +11,19 @@
11
11
 
12
12
  #define NewCipher(klass) \
13
13
  TypedData_Wrap_Struct((klass), &ossl_cipher_type, 0)
14
- #define MakeCipher(obj, klass, ctx) \
15
- (obj) = TypedData_Make_Struct((klass), EVP_CIPHER_CTX, &ossl_cipher_type, (ctx))
16
- #define AllocCipher(obj, ctx) \
17
- (DATA_PTR(obj) = (ctx) = ZALLOC(EVP_CIPHER_CTX))
14
+ #define AllocCipher(obj, ctx) do { \
15
+ (ctx) = EVP_CIPHER_CTX_new(); \
16
+ if (!(ctx)) \
17
+ ossl_raise(rb_eRuntimeError, NULL); \
18
+ RTYPEDDATA_DATA(obj) = (ctx); \
19
+ } while (0)
18
20
  #define GetCipherInit(obj, ctx) do { \
19
21
  TypedData_Get_Struct((obj), EVP_CIPHER_CTX, &ossl_cipher_type, (ctx)); \
20
22
  } while (0)
21
23
  #define GetCipher(obj, ctx) do { \
22
24
  GetCipherInit((obj), (ctx)); \
23
25
  if (!(ctx)) { \
24
- ossl_raise(rb_eRuntimeError, "Cipher not inititalized!"); \
26
+ ossl_raise(rb_eRuntimeError, "Cipher not initialized!"); \
25
27
  } \
26
28
  } while (0)
27
29
  #define SafeGetCipher(obj, ctx) do { \
@@ -34,16 +36,17 @@
34
36
  */
35
37
  VALUE cCipher;
36
38
  VALUE eCipherError;
39
+ static ID id_auth_tag_len, id_key_set;
37
40
 
38
41
  static VALUE ossl_cipher_alloc(VALUE klass);
39
42
  static void ossl_cipher_free(void *ptr);
40
- static size_t ossl_cipher_memsize(const void *ptr);
41
43
 
42
44
  static const rb_data_type_t ossl_cipher_type = {
43
45
  "OpenSSL/Cipher",
44
- {0, ossl_cipher_free, ossl_cipher_memsize,},
45
- 0, 0,
46
- RUBY_TYPED_FREE_IMMEDIATELY,
46
+ {
47
+ 0, ossl_cipher_free,
48
+ },
49
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
47
50
  };
48
51
 
49
52
  /*
@@ -52,11 +55,24 @@ static const rb_data_type_t ossl_cipher_type = {
52
55
  const EVP_CIPHER *
53
56
  GetCipherPtr(VALUE obj)
54
57
  {
55
- EVP_CIPHER_CTX *ctx;
58
+ if (rb_obj_is_kind_of(obj, cCipher)) {
59
+ EVP_CIPHER_CTX *ctx;
60
+
61
+ GetCipher(obj, ctx);
56
62
 
57
- SafeGetCipher(obj, ctx);
63
+ return EVP_CIPHER_CTX_cipher(ctx);
64
+ }
65
+ else {
66
+ const EVP_CIPHER *cipher;
58
67
 
59
- return EVP_CIPHER_CTX_cipher(ctx);
68
+ StringValueCStr(obj);
69
+ cipher = EVP_get_cipherbyname(RSTRING_PTR(obj));
70
+ if (!cipher)
71
+ ossl_raise(rb_eArgError,
72
+ "unsupported cipher algorithm: %"PRIsVALUE, obj);
73
+
74
+ return cipher;
75
+ }
60
76
  }
61
77
 
62
78
  VALUE
@@ -67,7 +83,6 @@ ossl_cipher_new(const EVP_CIPHER *cipher)
67
83
 
68
84
  ret = ossl_cipher_alloc(cCipher);
69
85
  AllocCipher(ret, ctx);
70
- EVP_CIPHER_CTX_init(ctx);
71
86
  if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)
72
87
  ossl_raise(eCipherError, NULL);
73
88
 
@@ -80,18 +95,7 @@ ossl_cipher_new(const EVP_CIPHER *cipher)
80
95
  static void
81
96
  ossl_cipher_free(void *ptr)
82
97
  {
83
- EVP_CIPHER_CTX *ctx = ptr;
84
- if (ctx) {
85
- EVP_CIPHER_CTX_cleanup(ctx);
86
- ruby_xfree(ctx);
87
- }
88
- }
89
-
90
- static size_t
91
- ossl_cipher_memsize(const void *ptr)
92
- {
93
- const EVP_CIPHER_CTX *ctx = ptr;
94
- return sizeof(*ctx);
98
+ EVP_CIPHER_CTX_free(ptr);
95
99
  }
96
100
 
97
101
  static VALUE
@@ -114,26 +118,17 @@ ossl_cipher_initialize(VALUE self, VALUE str)
114
118
  EVP_CIPHER_CTX *ctx;
115
119
  const EVP_CIPHER *cipher;
116
120
  char *name;
117
- unsigned char key[EVP_MAX_KEY_LENGTH];
118
121
 
119
- name = StringValuePtr(str);
122
+ name = StringValueCStr(str);
120
123
  GetCipherInit(self, ctx);
121
124
  if (ctx) {
122
- ossl_raise(rb_eRuntimeError, "Cipher already inititalized!");
125
+ ossl_raise(rb_eRuntimeError, "Cipher already initialized!");
123
126
  }
124
127
  AllocCipher(self, ctx);
125
- EVP_CIPHER_CTX_init(ctx);
126
128
  if (!(cipher = EVP_get_cipherbyname(name))) {
127
- ossl_raise(rb_eRuntimeError, "unsupported cipher algorithm (%s)", name);
129
+ ossl_raise(rb_eRuntimeError, "unsupported cipher algorithm (%"PRIsVALUE")", str);
128
130
  }
129
- /*
130
- * The EVP which has EVP_CIPH_RAND_KEY flag (such as DES3) allows
131
- * uninitialized key, but other EVPs (such as AES) does not allow it.
132
- * Calling EVP_CipherUpdate() without initializing key causes SEGV so we
133
- * set the data filled with "\0" as the key by default.
134
- */
135
- memset(key, 0, EVP_MAX_KEY_LENGTH);
136
- if (EVP_CipherInit_ex(ctx, cipher, NULL, key, NULL, -1) != 1)
131
+ if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)
137
132
  ossl_raise(eCipherError, NULL);
138
133
 
139
134
  return self;
@@ -158,16 +153,13 @@ ossl_cipher_copy(VALUE self, VALUE other)
158
153
  return self;
159
154
  }
160
155
 
161
- #ifdef HAVE_OBJ_NAME_DO_ALL_SORTED
162
156
  static void*
163
157
  add_cipher_name_to_ary(const OBJ_NAME *name, VALUE ary)
164
158
  {
165
159
  rb_ary_push(ary, rb_str_new2(name->name));
166
160
  return NULL;
167
161
  }
168
- #endif
169
162
 
170
- #ifdef HAVE_OBJ_NAME_DO_ALL_SORTED
171
163
  /*
172
164
  * call-seq:
173
165
  * OpenSSL::Cipher.ciphers -> array[string...]
@@ -186,9 +178,6 @@ ossl_s_ciphers(VALUE self)
186
178
 
187
179
  return ary;
188
180
  }
189
- #else
190
- #define ossl_s_ciphers rb_f_notimplement
191
- #endif
192
181
 
193
182
  /*
194
183
  * call-seq:
@@ -252,6 +241,9 @@ ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode)
252
241
  ossl_raise(eCipherError, NULL);
253
242
  }
254
243
 
244
+ if (p_key)
245
+ rb_ivar_set(self, id_key_set, Qtrue);
246
+
255
247
  return self;
256
248
  }
257
249
 
@@ -263,7 +255,7 @@ ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode)
263
255
  *
264
256
  * Make sure to call Cipher#encrypt or Cipher#decrypt before using any of the
265
257
  * following methods:
266
- * * [key=, iv=, random_key, random_iv, pkcs5_keyivgen]
258
+ * * [#key=, #iv=, #random_key, #random_iv, #pkcs5_keyivgen]
267
259
  *
268
260
  * Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 1).
269
261
  */
@@ -281,7 +273,7 @@ ossl_cipher_encrypt(int argc, VALUE *argv, VALUE self)
281
273
  *
282
274
  * Make sure to call Cipher#encrypt or Cipher#decrypt before using any of the
283
275
  * following methods:
284
- * * [key=, iv=, random_key, random_iv, pkcs5_keyivgen]
276
+ * * [#key=, #iv=, #random_key, #random_iv, #pkcs5_keyivgen]
285
277
  *
286
278
  * Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 0).
287
279
  */
@@ -293,20 +285,20 @@ ossl_cipher_decrypt(int argc, VALUE *argv, VALUE self)
293
285
 
294
286
  /*
295
287
  * call-seq:
296
- * cipher.pkcs5_keyivgen(pass [, salt [, iterations [, digest]]] ) -> nil
288
+ * cipher.pkcs5_keyivgen(pass, salt = nil, iterations = 2048, digest = "MD5") -> nil
297
289
  *
298
290
  * Generates and sets the key/IV based on a password.
299
291
  *
300
- * WARNING: This method is only PKCS5 v1.5 compliant when using RC2, RC4-40,
292
+ * *WARNING*: This method is only PKCS5 v1.5 compliant when using RC2, RC4-40,
301
293
  * or DES with MD5 or SHA1. Using anything else (like AES) will generate the
302
294
  * key/iv using an OpenSSL specific method. This method is deprecated and
303
295
  * should no longer be used. Use a PKCS5 v2 key generation method from
304
296
  * OpenSSL::PKCS5 instead.
305
297
  *
306
298
  * === Parameters
307
- * +salt+ must be an 8 byte string if provided.
308
- * +iterations+ is a integer with a default of 2048.
309
- * +digest+ is a Digest object that defaults to 'MD5'
299
+ * * +salt+ must be an 8 byte string if provided.
300
+ * * +iterations+ is an integer with a default of 2048.
301
+ * * +digest+ is a Digest object that defaults to 'MD5'
310
302
  *
311
303
  * A minimum of 1000 iterations is recommended.
312
304
  *
@@ -329,6 +321,8 @@ ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
329
321
  salt = (unsigned char *)RSTRING_PTR(vsalt);
330
322
  }
331
323
  iter = NIL_P(viter) ? 2048 : NUM2INT(viter);
324
+ if (iter <= 0)
325
+ rb_raise(rb_eArgError, "iterations must be a positive integer");
332
326
  digest = NIL_P(vdigest) ? EVP_md5() : GetDigestPtr(vdigest);
333
327
  GetCipher(self, ctx);
334
328
  EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), digest, salt,
@@ -338,6 +332,8 @@ ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
338
332
  OPENSSL_cleanse(key, sizeof key);
339
333
  OPENSSL_cleanse(iv, sizeof iv);
340
334
 
335
+ rb_ivar_set(self, id_key_set, Qtrue);
336
+
341
337
  return Qnil;
342
338
  }
343
339
 
@@ -346,25 +342,23 @@ ossl_cipher_update_long(EVP_CIPHER_CTX *ctx, unsigned char *out, long *out_len_p
346
342
  const unsigned char *in, long in_len)
347
343
  {
348
344
  int out_part_len;
345
+ int limit = INT_MAX / 2 + 1;
349
346
  long out_len = 0;
350
- #define UPDATE_LENGTH_LIMIT INT_MAX
351
-
352
- #if SIZEOF_LONG > UPDATE_LENGTH_LIMIT
353
- if (in_len > UPDATE_LENGTH_LIMIT) {
354
- const int in_part_len = (UPDATE_LENGTH_LIMIT / 2 + 1) & ~1;
355
- do {
356
- if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0,
357
- &out_part_len, in, in_part_len))
358
- return 0;
359
- out_len += out_part_len;
360
- in += in_part_len;
361
- } while ((in_len -= in_part_len) > UPDATE_LENGTH_LIMIT);
362
- }
363
- #endif
364
- if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0,
365
- &out_part_len, in, (int)in_len))
366
- return 0;
367
- if (out_len_ptr) *out_len_ptr = out_len += out_part_len;
347
+
348
+ do {
349
+ int in_part_len = in_len > limit ? limit : (int)in_len;
350
+
351
+ if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0,
352
+ &out_part_len, in, in_part_len))
353
+ return 0;
354
+
355
+ out_len += out_part_len;
356
+ in += in_part_len;
357
+ } while ((in_len -= limit) > 0);
358
+
359
+ if (out_len_ptr)
360
+ *out_len_ptr = out_len;
361
+
368
362
  return 1;
369
363
  }
370
364
 
@@ -377,9 +371,8 @@ ossl_cipher_update_long(EVP_CIPHER_CTX *ctx, unsigned char *out, long *out_len_p
377
371
  * data chunk. When done, the output of Cipher#final should be additionally
378
372
  * added to the result.
379
373
  *
380
- * === Parameters
381
- * +data+ is a nonempty string.
382
- * +buffer+ is an optional string to store the result.
374
+ * If +buffer+ is given, the encryption/decryption result will be written to
375
+ * it. +buffer+ will be resized automatically.
383
376
  */
384
377
  static VALUE
385
378
  ossl_cipher_update(int argc, VALUE *argv, VALUE self)
@@ -391,6 +384,9 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
391
384
 
392
385
  rb_scan_args(argc, argv, "11", &data, &str);
393
386
 
387
+ if (!RTEST(rb_attr_get(self, id_key_set)))
388
+ ossl_raise(eCipherError, "key not set");
389
+
394
390
  StringValue(data);
395
391
  in = (unsigned char *)RSTRING_PTR(data);
396
392
  if ((in_len = RSTRING_LEN(data)) == 0)
@@ -424,7 +420,7 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
424
420
  * Returns the remaining data held in the cipher object. Further calls to
425
421
  * Cipher#update or Cipher#final will return garbage. This call should always
426
422
  * be made as the last call of an encryption or decryption operation, after
427
- * after having fed the entire plaintext or ciphertext to the Cipher instance.
423
+ * having fed the entire plaintext or ciphertext to the Cipher instance.
428
424
  *
429
425
  * If an authenticated cipher was used, a CipherError is raised if the tag
430
426
  * could not be authenticated successfully. Only call this method after
@@ -480,15 +476,19 @@ static VALUE
480
476
  ossl_cipher_set_key(VALUE self, VALUE key)
481
477
  {
482
478
  EVP_CIPHER_CTX *ctx;
479
+ int key_len;
483
480
 
484
481
  StringValue(key);
485
482
  GetCipher(self, ctx);
486
483
 
487
- if (RSTRING_LEN(key) < EVP_CIPHER_CTX_key_length(ctx))
488
- ossl_raise(eCipherError, "key length too short");
484
+ key_len = EVP_CIPHER_CTX_key_length(ctx);
485
+ if (RSTRING_LEN(key) != key_len)
486
+ ossl_raise(rb_eArgError, "key must be %d bytes", key_len);
489
487
 
490
488
  if (EVP_CipherInit_ex(ctx, NULL, NULL, (unsigned char *)RSTRING_PTR(key), NULL, -1) != 1)
491
- ossl_raise(eCipherError, NULL);
489
+ ossl_raise(eCipherError, NULL);
490
+
491
+ rb_ivar_set(self, id_key_set, Qtrue);
492
492
 
493
493
  return key;
494
494
  }
@@ -504,20 +504,24 @@ ossl_cipher_set_key(VALUE self, VALUE key)
504
504
  * Cipher#random_iv to create a secure random IV.
505
505
  *
506
506
  * Only call this method after calling Cipher#encrypt or Cipher#decrypt.
507
- *
508
- * If not explicitly set, the OpenSSL default of an all-zeroes ("\\0") IV is
509
- * used.
510
507
  */
511
508
  static VALUE
512
509
  ossl_cipher_set_iv(VALUE self, VALUE iv)
513
510
  {
514
511
  EVP_CIPHER_CTX *ctx;
512
+ int iv_len = 0;
515
513
 
516
514
  StringValue(iv);
517
515
  GetCipher(self, ctx);
518
516
 
519
- if (RSTRING_LEN(iv) < EVP_CIPHER_CTX_iv_length(ctx))
520
- ossl_raise(eCipherError, "iv length too short");
517
+ #if defined(HAVE_AUTHENTICATED_ENCRYPTION)
518
+ if (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER)
519
+ iv_len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
520
+ #endif
521
+ if (!iv_len)
522
+ iv_len = EVP_CIPHER_CTX_iv_length(ctx);
523
+ if (RSTRING_LEN(iv) != iv_len)
524
+ ossl_raise(rb_eArgError, "iv must be %d bytes", iv_len);
521
525
 
522
526
  if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, (unsigned char *)RSTRING_PTR(iv), -1) != 1)
523
527
  ossl_raise(eCipherError, NULL);
@@ -525,6 +529,27 @@ ossl_cipher_set_iv(VALUE self, VALUE iv)
525
529
  return iv;
526
530
  }
527
531
 
532
+ /*
533
+ * call-seq:
534
+ * cipher.authenticated? -> true | false
535
+ *
536
+ * Indicated whether this Cipher instance uses an Authenticated Encryption
537
+ * mode.
538
+ */
539
+ static VALUE
540
+ ossl_cipher_is_authenticated(VALUE self)
541
+ {
542
+ EVP_CIPHER_CTX *ctx;
543
+
544
+ GetCipher(self, ctx);
545
+
546
+ #if defined(HAVE_AUTHENTICATED_ENCRYPTION)
547
+ return (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER) ? Qtrue : Qfalse;
548
+ #else
549
+ return Qfalse;
550
+ #endif
551
+ }
552
+
528
553
  #ifdef HAVE_AUTHENTICATED_ENCRYPTION
529
554
  /*
530
555
  * call-seq:
@@ -557,6 +582,8 @@ ossl_cipher_set_auth_data(VALUE self, VALUE data)
557
582
  in_len = RSTRING_LEN(data);
558
583
 
559
584
  GetCipher(self, ctx);
585
+ if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
586
+ ossl_raise(eCipherError, "AEAD not supported by this cipher");
560
587
 
561
588
  if (!ossl_cipher_update_long(ctx, NULL, &out_len, in, in_len))
562
589
  ossl_raise(eCipherError, "couldn't set additional authenticated data");
@@ -564,88 +591,63 @@ ossl_cipher_set_auth_data(VALUE self, VALUE data)
564
591
  return data;
565
592
  }
566
593
 
567
- #define ossl_is_gcm(nid) (nid) == NID_aes_128_gcm || \
568
- (nid) == NID_aes_192_gcm || \
569
- (nid) == NID_aes_256_gcm
570
-
571
- static VALUE
572
- ossl_get_gcm_auth_tag(EVP_CIPHER_CTX *ctx, int len)
573
- {
574
- unsigned char *tag;
575
- VALUE ret;
576
-
577
- tag = ALLOC_N(unsigned char, len);
578
-
579
- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, len, tag))
580
- ossl_raise(eCipherError, "retrieving the authentication tag failed");
581
-
582
- ret = rb_str_new((const char *) tag, len);
583
- xfree(tag);
584
- return ret;
585
- }
586
-
587
594
  /*
588
595
  * call-seq:
589
- * cipher.auth_tag([ tag_len ] -> string
596
+ * cipher.auth_tag(tag_len = 16) -> String
590
597
  *
591
598
  * Gets the authentication tag generated by Authenticated Encryption Cipher
592
599
  * modes (GCM for example). This tag may be stored along with the ciphertext,
593
600
  * then set on the decryption cipher to authenticate the contents of the
594
601
  * ciphertext against changes. If the optional integer parameter +tag_len+ is
595
602
  * given, the returned tag will be +tag_len+ bytes long. If the parameter is
596
- * omitted, the maximum length of 16 bytes will be returned. For maximum
597
- * security, the default of 16 bytes should be chosen.
603
+ * omitted, the default length of 16 bytes or the length previously set by
604
+ * #auth_tag_len= will be used. For maximum security, the longest possible
605
+ * should be chosen.
598
606
  *
599
607
  * The tag may only be retrieved after calling Cipher#final.
600
608
  */
601
609
  static VALUE
602
610
  ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self)
603
611
  {
604
- VALUE vtag_len;
612
+ VALUE vtag_len, ret;
605
613
  EVP_CIPHER_CTX *ctx;
606
- int nid, tag_len;
614
+ int tag_len = 16;
607
615
 
608
- if (rb_scan_args(argc, argv, "01", &vtag_len) == 0) {
609
- tag_len = 16;
610
- } else {
616
+ rb_scan_args(argc, argv, "01", &vtag_len);
617
+ if (NIL_P(vtag_len))
618
+ vtag_len = rb_attr_get(self, id_auth_tag_len);
619
+ if (!NIL_P(vtag_len))
611
620
  tag_len = NUM2INT(vtag_len);
612
- }
613
621
 
614
622
  GetCipher(self, ctx);
615
- nid = EVP_CIPHER_CTX_nid(ctx);
616
623
 
617
- if (ossl_is_gcm(nid)) {
618
- return ossl_get_gcm_auth_tag(ctx, tag_len);
619
- } else {
624
+ if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER))
620
625
  ossl_raise(eCipherError, "authentication tag not supported by this cipher");
621
- return Qnil; /* dummy */
622
- }
623
- }
624
626
 
625
- static inline void
626
- ossl_set_gcm_auth_tag(EVP_CIPHER_CTX *ctx, unsigned char *tag, int tag_len)
627
- {
628
- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_len, tag))
629
- ossl_raise(eCipherError, "unable to set GCM tag");
627
+ ret = rb_str_new(NULL, tag_len);
628
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, RSTRING_PTR(ret)))
629
+ ossl_raise(eCipherError, "retrieving the authentication tag failed");
630
+
631
+ return ret;
630
632
  }
631
633
 
632
634
  /*
633
635
  * call-seq:
634
636
  * cipher.auth_tag = string -> string
635
637
  *
636
- * Sets the authentication tag to verify the contents of the
637
- * ciphertext. The tag must be set after calling Cipher#decrypt,
638
- * Cipher#key= and Cipher#iv=, but before assigning the associated
639
- * authenticated data using Cipher#auth_data= and of course, before
640
- * decrypting any of the ciphertext. After all decryption is
641
- * performed, the tag is verified automatically in the call to
642
- * Cipher#final.
638
+ * Sets the authentication tag to verify the integrity of the ciphertext.
639
+ * This can be called only when the cipher supports AE. The tag must be set
640
+ * after calling Cipher#decrypt, Cipher#key= and Cipher#iv=, but before
641
+ * calling Cipher#final. After all decryption is performed, the tag is
642
+ * verified automatically in the call to Cipher#final.
643
+ *
644
+ * For OCB mode, the tag length must be supplied with #auth_tag_len=
645
+ * beforehand.
643
646
  */
644
647
  static VALUE
645
648
  ossl_cipher_set_auth_tag(VALUE self, VALUE vtag)
646
649
  {
647
650
  EVP_CIPHER_CTX *ctx;
648
- int nid;
649
651
  unsigned char *tag;
650
652
  int tag_len;
651
653
 
@@ -654,44 +656,80 @@ ossl_cipher_set_auth_tag(VALUE self, VALUE vtag)
654
656
  tag_len = RSTRING_LENINT(vtag);
655
657
 
656
658
  GetCipher(self, ctx);
657
- nid = EVP_CIPHER_CTX_nid(ctx);
658
-
659
- if (ossl_is_gcm(nid)) {
660
- ossl_set_gcm_auth_tag(ctx, tag, tag_len);
661
- } else {
659
+ if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER))
662
660
  ossl_raise(eCipherError, "authentication tag not supported by this cipher");
663
- }
661
+
662
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, tag))
663
+ ossl_raise(eCipherError, "unable to set AEAD tag");
664
664
 
665
665
  return vtag;
666
666
  }
667
667
 
668
668
  /*
669
669
  * call-seq:
670
- * cipher.authenticated? -> boolean
670
+ * cipher.auth_tag_len = Integer -> Integer
671
671
  *
672
- * Indicated whether this Cipher instance uses an Authenticated Encryption
673
- * mode.
672
+ * Sets the length of the authentication tag to be generated or to be given for
673
+ * AEAD ciphers that requires it as in input parameter. Note that not all AEAD
674
+ * ciphers support this method.
675
+ *
676
+ * In OCB mode, the length must be supplied both when encrypting and when
677
+ * decrypting, and must be before specifying an IV.
674
678
  */
675
679
  static VALUE
676
- ossl_cipher_is_authenticated(VALUE self)
680
+ ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen)
677
681
  {
682
+ int tag_len = NUM2INT(vlen);
678
683
  EVP_CIPHER_CTX *ctx;
679
- int nid;
680
684
 
681
685
  GetCipher(self, ctx);
682
- nid = EVP_CIPHER_CTX_nid(ctx);
686
+ if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER))
687
+ ossl_raise(eCipherError, "AEAD not supported by this cipher");
683
688
 
684
- if (ossl_is_gcm(nid)) {
685
- return Qtrue;
686
- } else {
687
- return Qfalse;
688
- }
689
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, NULL))
690
+ ossl_raise(eCipherError, "unable to set authentication tag length");
691
+
692
+ /* for #auth_tag */
693
+ rb_ivar_set(self, id_auth_tag_len, INT2NUM(tag_len));
694
+
695
+ return vlen;
696
+ }
697
+
698
+ /*
699
+ * call-seq:
700
+ * cipher.iv_len = integer -> integer
701
+ *
702
+ * Sets the IV/nonce length of the Cipher. Normally block ciphers don't allow
703
+ * changing the IV length, but some make use of IV for 'nonce'. You may need
704
+ * this for interoperability with other applications.
705
+ */
706
+ static VALUE
707
+ ossl_cipher_set_iv_length(VALUE self, VALUE iv_length)
708
+ {
709
+ int len = NUM2INT(iv_length);
710
+ EVP_CIPHER_CTX *ctx;
711
+
712
+ GetCipher(self, ctx);
713
+ if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER))
714
+ ossl_raise(eCipherError, "cipher does not support AEAD");
715
+
716
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, len, NULL))
717
+ ossl_raise(eCipherError, "unable to set IV length");
718
+
719
+ /*
720
+ * EVP_CIPHER_CTX_iv_length() returns the default length. So we need to save
721
+ * the length somewhere. Luckily currently we aren't using app_data.
722
+ */
723
+ EVP_CIPHER_CTX_set_app_data(ctx, (void *)(VALUE)len);
724
+
725
+ return iv_length;
689
726
  }
690
727
  #else
691
728
  #define ossl_cipher_set_auth_data rb_f_notimplement
692
729
  #define ossl_cipher_get_auth_tag rb_f_notimplement
693
730
  #define ossl_cipher_set_auth_tag rb_f_notimplement
694
- #define ossl_cipher_is_authenticated rb_f_notimplement
731
+ #define ossl_cipher_set_auth_tag_len rb_f_notimplement
732
+ #define ossl_cipher_set_iv_length rb_f_notimplement
695
733
  #endif
696
734
 
697
735
  /*
@@ -719,7 +757,6 @@ ossl_cipher_set_key_length(VALUE self, VALUE key_length)
719
757
  return key_length;
720
758
  }
721
759
 
722
- #if defined(HAVE_EVP_CIPHER_CTX_SET_PADDING)
723
760
  /*
724
761
  * call-seq:
725
762
  * cipher.padding = integer -> integer
@@ -741,18 +778,6 @@ ossl_cipher_set_padding(VALUE self, VALUE padding)
741
778
  ossl_raise(eCipherError, NULL);
742
779
  return padding;
743
780
  }
744
- #else
745
- #define ossl_cipher_set_padding rb_f_notimplement
746
- #endif
747
-
748
- #define CIPHER_0ARG_INT(func) \
749
- static VALUE \
750
- ossl_cipher_##func(VALUE self) \
751
- { \
752
- EVP_CIPHER_CTX *ctx; \
753
- GetCipher(self, ctx); \
754
- return INT2NUM(EVP_CIPHER_##func(EVP_CIPHER_CTX_cipher(ctx))); \
755
- }
756
781
 
757
782
  /*
758
783
  * call-seq:
@@ -760,21 +785,54 @@ ossl_cipher_set_padding(VALUE self, VALUE padding)
760
785
  *
761
786
  * Returns the key length in bytes of the Cipher.
762
787
  */
763
- CIPHER_0ARG_INT(key_length)
788
+ static VALUE
789
+ ossl_cipher_key_length(VALUE self)
790
+ {
791
+ EVP_CIPHER_CTX *ctx;
792
+
793
+ GetCipher(self, ctx);
794
+
795
+ return INT2NUM(EVP_CIPHER_CTX_key_length(ctx));
796
+ }
797
+
764
798
  /*
765
799
  * call-seq:
766
800
  * cipher.iv_len -> integer
767
801
  *
768
802
  * Returns the expected length in bytes for an IV for this Cipher.
769
803
  */
770
- CIPHER_0ARG_INT(iv_length)
804
+ static VALUE
805
+ ossl_cipher_iv_length(VALUE self)
806
+ {
807
+ EVP_CIPHER_CTX *ctx;
808
+ int len = 0;
809
+
810
+ GetCipher(self, ctx);
811
+ #if defined(HAVE_AUTHENTICATED_ENCRYPTION)
812
+ if (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER)
813
+ len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
814
+ #endif
815
+ if (!len)
816
+ len = EVP_CIPHER_CTX_iv_length(ctx);
817
+
818
+ return INT2NUM(len);
819
+ }
820
+
771
821
  /*
772
822
  * call-seq:
773
823
  * cipher.block_size -> integer
774
824
  *
775
825
  * Returns the size in bytes of the blocks on which this Cipher operates on.
776
826
  */
777
- CIPHER_0ARG_INT(block_size)
827
+ static VALUE
828
+ ossl_cipher_block_size(VALUE self)
829
+ {
830
+ EVP_CIPHER_CTX *ctx;
831
+
832
+ GetCipher(self, ctx);
833
+
834
+ return INT2NUM(EVP_CIPHER_CTX_block_size(ctx));
835
+ }
778
836
 
779
837
  /*
780
838
  * INIT
@@ -783,7 +841,8 @@ void
783
841
  Init_ossl_cipher(void)
784
842
  {
785
843
  #if 0
786
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
844
+ mOSSL = rb_define_module("OpenSSL");
845
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
787
846
  #endif
788
847
 
789
848
  /* Document-class: OpenSSL::Cipher
@@ -882,12 +941,10 @@ Init_ossl_cipher(void)
882
941
  * you absolutely need it</b>
883
942
  *
884
943
  * Because of this, you will end up with a mode that explicitly requires
885
- * an IV in any case. Note that for backwards compatibility reasons,
886
- * setting an IV is not explicitly mandated by the Cipher API. If not
887
- * set, OpenSSL itself defaults to an all-zeroes IV ("\\0", not the
888
- * character). Although the IV can be seen as public information, i.e.
889
- * it may be transmitted in public once generated, it should still stay
890
- * unpredictable to prevent certain kinds of attacks. Therefore, ideally
944
+ * an IV in any case. Although the IV can be seen as public information,
945
+ * i.e. it may be transmitted in public once generated, it should still
946
+ * stay unpredictable to prevent certain kinds of attacks. Therefore,
947
+ * ideally
891
948
  *
892
949
  * <b>Always create a secure random IV for every encryption of your
893
950
  * Cipher</b>
@@ -896,16 +953,16 @@ Init_ossl_cipher(void)
896
953
  * of the IV as a nonce (number used once) - it's public but random and
897
954
  * unpredictable. A secure random IV can be created as follows
898
955
  *
899
- * cipher = ...
900
- * cipher.encrypt
901
- * key = cipher.random_key
902
- * iv = cipher.random_iv # also sets the generated IV on the Cipher
956
+ * cipher = ...
957
+ * cipher.encrypt
958
+ * key = cipher.random_key
959
+ * iv = cipher.random_iv # also sets the generated IV on the Cipher
903
960
  *
904
- * Although the key is generally a random value, too, it is a bad choice
905
- * as an IV. There are elaborate ways how an attacker can take advantage
906
- * of such an IV. As a general rule of thumb, exposing the key directly
907
- * or indirectly should be avoided at all cost and exceptions only be
908
- * made with good reason.
961
+ * Although the key is generally a random value, too, it is a bad choice
962
+ * as an IV. There are elaborate ways how an attacker can take advantage
963
+ * of such an IV. As a general rule of thumb, exposing the key directly
964
+ * or indirectly should be avoided at all cost and exceptions only be
965
+ * made with good reason.
909
966
  *
910
967
  * === Calling Cipher#final
911
968
  *
@@ -959,29 +1016,42 @@ Init_ossl_cipher(void)
959
1016
  * could otherwise be exploited to modify ciphertexts in ways beneficial to
960
1017
  * potential attackers.
961
1018
  *
962
- * If no associated data is needed for encryption and later decryption,
963
- * the OpenSSL library still requires a value to be set - "" may be used in
964
- * case none is available. An example using the GCM (Galois Counter Mode):
1019
+ * An associated data is used where there is additional information, such as
1020
+ * headers or some metadata, that must be also authenticated but not
1021
+ * necessarily need to be encrypted. If no associated data is needed for
1022
+ * encryption and later decryption, the OpenSSL library still requires a
1023
+ * value to be set - "" may be used in case none is available.
965
1024
  *
966
- * cipher = OpenSSL::Cipher::AES.new(128, :GCM)
967
- * cipher.encrypt
968
- * key = cipher.random_key
969
- * iv = cipher.random_iv
970
- * cipher.auth_data = ""
1025
+ * An example using the GCM (Galois/Counter Mode). You have 16 bytes +key+,
1026
+ * 12 bytes (96 bits) +nonce+ and the associated data +auth_data+. Be sure
1027
+ * not to reuse the +key+ and +nonce+ pair. Reusing an nonce ruins the
1028
+ * security guarantees of GCM mode.
1029
+ *
1030
+ * cipher = OpenSSL::Cipher::AES.new(128, :GCM).encrypt
1031
+ * cipher.key = key
1032
+ * cipher.iv = nonce
1033
+ * cipher.auth_data = auth_data
971
1034
  *
972
1035
  * encrypted = cipher.update(data) + cipher.final
973
- * tag = cipher.auth_tag
1036
+ * tag = cipher.auth_tag # produces 16 bytes tag by default
974
1037
  *
975
- * decipher = OpenSSL::Cipher::AES.new(128, :GCM)
976
- * decipher.decrypt
1038
+ * Now you are the receiver. You know the +key+ and have received +nonce+,
1039
+ * +auth_data+, +encrypted+ and +tag+ through an untrusted network. Note
1040
+ * that GCM accepts an arbitrary length tag between 1 and 16 bytes. You may
1041
+ * additionally need to check that the received tag has the correct length,
1042
+ * or you allow attackers to forge a valid single byte tag for the tampered
1043
+ * ciphertext with a probability of 1/256.
1044
+ *
1045
+ * raise "tag is truncated!" unless tag.bytesize == 16
1046
+ * decipher = OpenSSL::Cipher::AES.new(128, :GCM).decrypt
977
1047
  * decipher.key = key
978
- * decipher.iv = iv
1048
+ * decipher.iv = nonce
979
1049
  * decipher.auth_tag = tag
980
- * decipher.auth_data = ""
1050
+ * decipher.auth_data = auth_data
981
1051
  *
982
- * plain = decipher.update(encrypted) + decipher.final
1052
+ * decrypted = decipher.update(encrypted) + decipher.final
983
1053
  *
984
- * puts data == plain #=> true
1054
+ * puts data == decrypted #=> true
985
1055
  */
986
1056
  cCipher = rb_define_class_under(mOSSL, "Cipher", rb_cObject);
987
1057
  eCipherError = rb_define_class_under(cCipher, "CipherError", eOSSLError);
@@ -1001,11 +1071,16 @@ Init_ossl_cipher(void)
1001
1071
  rb_define_method(cCipher, "auth_data=", ossl_cipher_set_auth_data, 1);
1002
1072
  rb_define_method(cCipher, "auth_tag=", ossl_cipher_set_auth_tag, 1);
1003
1073
  rb_define_method(cCipher, "auth_tag", ossl_cipher_get_auth_tag, -1);
1074
+ rb_define_method(cCipher, "auth_tag_len=", ossl_cipher_set_auth_tag_len, 1);
1004
1075
  rb_define_method(cCipher, "authenticated?", ossl_cipher_is_authenticated, 0);
1005
1076
  rb_define_method(cCipher, "key_len=", ossl_cipher_set_key_length, 1);
1006
1077
  rb_define_method(cCipher, "key_len", ossl_cipher_key_length, 0);
1007
1078
  rb_define_method(cCipher, "iv=", ossl_cipher_set_iv, 1);
1079
+ rb_define_method(cCipher, "iv_len=", ossl_cipher_set_iv_length, 1);
1008
1080
  rb_define_method(cCipher, "iv_len", ossl_cipher_iv_length, 0);
1009
1081
  rb_define_method(cCipher, "block_size", ossl_cipher_block_size, 0);
1010
1082
  rb_define_method(cCipher, "padding=", ossl_cipher_set_padding, 1);
1083
+
1084
+ id_auth_tag_len = rb_intern_const("auth_tag_len");
1085
+ id_key_set = rb_intern_const("key_set");
1011
1086
  }