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.
- checksums.yaml +5 -5
- data/ext/rubysl/openssl/deprecation.rb +7 -3
- data/ext/rubysl/openssl/extconf.rb +148 -103
- data/ext/rubysl/openssl/openssl_missing.c +94 -275
- data/ext/rubysl/openssl/openssl_missing.h +167 -98
- data/ext/rubysl/openssl/ossl.c +266 -212
- data/ext/rubysl/openssl/ossl.h +27 -89
- data/ext/rubysl/openssl/ossl_asn1.c +157 -221
- data/ext/rubysl/openssl/ossl_asn1.h +11 -3
- data/ext/rubysl/openssl/ossl_bio.c +10 -40
- data/ext/rubysl/openssl/ossl_bio.h +1 -2
- data/ext/rubysl/openssl/ossl_bn.c +144 -100
- data/ext/rubysl/openssl/ossl_bn.h +3 -1
- data/ext/rubysl/openssl/ossl_cipher.c +270 -195
- data/ext/rubysl/openssl/ossl_config.c +7 -1
- data/ext/rubysl/openssl/ossl_config.h +0 -1
- data/ext/rubysl/openssl/ossl_digest.c +40 -29
- data/ext/rubysl/openssl/ossl_engine.c +23 -62
- data/ext/rubysl/openssl/ossl_hmac.c +82 -55
- data/ext/rubysl/openssl/ossl_ns_spki.c +22 -22
- data/ext/rubysl/openssl/ossl_ocsp.c +894 -144
- data/ext/rubysl/openssl/ossl_ocsp.h +1 -1
- data/ext/rubysl/openssl/ossl_pkcs12.c +47 -19
- data/ext/rubysl/openssl/ossl_pkcs5.c +7 -15
- data/ext/rubysl/openssl/ossl_pkcs7.c +38 -15
- data/ext/rubysl/openssl/ossl_pkey.c +151 -99
- data/ext/rubysl/openssl/ossl_pkey.h +123 -29
- data/ext/rubysl/openssl/ossl_pkey_dh.c +143 -92
- data/ext/rubysl/openssl/ossl_pkey_dsa.c +149 -104
- data/ext/rubysl/openssl/ossl_pkey_ec.c +646 -524
- data/ext/rubysl/openssl/ossl_pkey_rsa.c +180 -121
- data/ext/rubysl/openssl/ossl_rand.c +25 -21
- data/ext/rubysl/openssl/ossl_ssl.c +795 -413
- data/ext/rubysl/openssl/ossl_ssl.h +3 -0
- data/ext/rubysl/openssl/ossl_ssl_session.c +83 -77
- data/ext/rubysl/openssl/ossl_version.h +1 -1
- data/ext/rubysl/openssl/ossl_x509.c +92 -8
- data/ext/rubysl/openssl/ossl_x509.h +14 -5
- data/ext/rubysl/openssl/ossl_x509attr.c +77 -41
- data/ext/rubysl/openssl/ossl_x509cert.c +45 -46
- data/ext/rubysl/openssl/ossl_x509crl.c +51 -57
- data/ext/rubysl/openssl/ossl_x509ext.c +39 -33
- data/ext/rubysl/openssl/ossl_x509name.c +68 -45
- data/ext/rubysl/openssl/ossl_x509req.c +32 -38
- data/ext/rubysl/openssl/ossl_x509revoked.c +43 -9
- data/ext/rubysl/openssl/ossl_x509store.c +309 -104
- data/ext/rubysl/openssl/ruby_missing.h +8 -6
- data/lib/openssl/buffering.rb +11 -5
- data/lib/openssl/cipher.rb +23 -15
- data/lib/openssl/digest.rb +7 -10
- data/lib/openssl/pkey.rb +15 -8
- data/lib/openssl/ssl.rb +81 -105
- data/lib/rubysl/openssl.rb +1 -4
- data/lib/rubysl/openssl/version.rb +1 -1
- 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 *
|
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
|
15
|
-
(
|
16
|
-
|
17
|
-
|
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
|
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
|
-
{
|
45
|
-
|
46
|
-
|
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
|
-
|
58
|
+
if (rb_obj_is_kind_of(obj, cCipher)) {
|
59
|
+
EVP_CIPHER_CTX *ctx;
|
60
|
+
|
61
|
+
GetCipher(obj, ctx);
|
56
62
|
|
57
|
-
|
63
|
+
return EVP_CIPHER_CTX_cipher(ctx);
|
64
|
+
}
|
65
|
+
else {
|
66
|
+
const EVP_CIPHER *cipher;
|
58
67
|
|
59
|
-
|
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
|
-
|
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 =
|
122
|
+
name = StringValueCStr(str);
|
120
123
|
GetCipherInit(self, ctx);
|
121
124
|
if (ctx) {
|
122
|
-
ossl_raise(rb_eRuntimeError, "Cipher already
|
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 (%
|
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
|
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
|
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
|
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
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
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
|
-
*
|
381
|
-
* +
|
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
|
-
*
|
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
|
-
|
488
|
-
|
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
|
-
|
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
|
-
|
520
|
-
|
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(
|
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
|
597
|
-
*
|
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
|
614
|
+
int tag_len = 16;
|
607
615
|
|
608
|
-
|
609
|
-
|
610
|
-
|
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 (
|
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
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
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
|
637
|
-
*
|
638
|
-
* Cipher#key= and Cipher#iv=, but before
|
639
|
-
*
|
640
|
-
*
|
641
|
-
*
|
642
|
-
*
|
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
|
-
|
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.
|
670
|
+
* cipher.auth_tag_len = Integer -> Integer
|
671
671
|
*
|
672
|
-
*
|
673
|
-
*
|
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
|
-
|
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
|
-
|
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 (
|
685
|
-
|
686
|
-
|
687
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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");
|
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.
|
886
|
-
*
|
887
|
-
*
|
888
|
-
*
|
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
|
-
*
|
900
|
-
*
|
901
|
-
*
|
902
|
-
*
|
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
|
-
*
|
905
|
-
*
|
906
|
-
*
|
907
|
-
*
|
908
|
-
*
|
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
|
-
*
|
963
|
-
*
|
964
|
-
*
|
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
|
-
*
|
967
|
-
*
|
968
|
-
*
|
969
|
-
*
|
970
|
-
*
|
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
|
-
*
|
976
|
-
*
|
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 =
|
1048
|
+
* decipher.iv = nonce
|
979
1049
|
* decipher.auth_tag = tag
|
980
|
-
* decipher.auth_data =
|
1050
|
+
* decipher.auth_data = auth_data
|
981
1051
|
*
|
982
|
-
*
|
1052
|
+
* decrypted = decipher.update(encrypted) + decipher.final
|
983
1053
|
*
|
984
|
-
* puts data ==
|
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
|
}
|