rubysl-openssl 2.10 → 2.11

Sign up to get free protection for your applications and to get access to all the features.
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
  }