aboutsummaryrefslogtreecommitdiffstats
path: root/ext/openssl/ossl_cipher.c
diff options
context:
space:
mode:
authorZachary Scott <e@zzak.io>2015-01-05 11:59:50 -0800
committerZachary Scott <e@zzak.io>2015-01-05 11:59:50 -0800
commit2953dfd4ad925a669110fed1993d6e83b24e420f (patch)
tree05e4d2a6750e0ce6dd408c2b8f2f5bf597cfe54a /ext/openssl/ossl_cipher.c
parent77269de78e376981342127d30dc0b953b9bcd781 (diff)
downloadruby-openssl-2953dfd4ad925a669110fed1993d6e83b24e420f.tar.gz
Sync with ruby trunk
Diffstat (limited to 'ext/openssl/ossl_cipher.c')
-rw-r--r--ext/openssl/ossl_cipher.c46
1 files changed, 38 insertions, 8 deletions
diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c
index 0efadd19..08fdacfb 100644
--- a/ext/openssl/ossl_cipher.c
+++ b/ext/openssl/ossl_cipher.c
@@ -43,7 +43,7 @@ static size_t ossl_cipher_memsize(const void *ptr);
static const rb_data_type_t ossl_cipher_type = {
"OpenSSL/Cipher",
{0, ossl_cipher_free, ossl_cipher_memsize,},
- NULL, NULL,
+ 0, 0,
RUBY_TYPED_FREE_IMMEDIATELY,
};
@@ -346,6 +346,33 @@ ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
return Qnil;
}
+static int
+ossl_cipher_update_long(EVP_CIPHER_CTX *ctx, unsigned char *out, long *out_len_ptr,
+ const unsigned char *in, long in_len)
+{
+ int out_part_len;
+ long out_len = 0;
+#define UPDATE_LENGTH_LIMIT INT_MAX
+
+#if SIZEOF_LONG > UPDATE_LENGTH_LIMIT
+ if (in_len > UPDATE_LENGTH_LIMIT) {
+ const int in_part_len = (UPDATE_LENGTH_LIMIT / 2 + 1) & ~1;
+ do {
+ if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0,
+ &out_part_len, in, in_part_len))
+ return 0;
+ out_len += out_part_len;
+ in += in_part_len;
+ } while ((in_len -= in_part_len) > UPDATE_LENGTH_LIMIT);
+ }
+#endif
+ if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0,
+ &out_part_len, in, (int)in_len))
+ return 0;
+ if (out_len_ptr) *out_len_ptr = out_len += out_part_len;
+ return 1;
+}
+
/*
* call-seq:
* cipher.update(data [, buffer]) -> string or buffer
@@ -364,17 +391,21 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
{
EVP_CIPHER_CTX *ctx;
unsigned char *in;
- int in_len, out_len;
+ long in_len, out_len;
VALUE data, str;
rb_scan_args(argc, argv, "11", &data, &str);
StringValue(data);
in = (unsigned char *)RSTRING_PTR(data);
- if ((in_len = RSTRING_LENINT(data)) == 0)
+ if ((in_len = RSTRING_LEN(data)) == 0)
ossl_raise(rb_eArgError, "data must not be empty");
GetCipher(self, ctx);
out_len = in_len+EVP_CIPHER_CTX_block_size(ctx);
+ if (out_len <= 0) {
+ ossl_raise(rb_eRangeError,
+ "data too big to make output buffer: %ld bytes", in_len);
+ }
if (NIL_P(str)) {
str = rb_str_new(0, out_len);
@@ -383,7 +414,7 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
rb_str_resize(str, out_len);
}
- if (!EVP_CipherUpdate(ctx, (unsigned char *)RSTRING_PTR(str), &out_len, in, in_len))
+ if (!ossl_cipher_update_long(ctx, (unsigned char *)RSTRING_PTR(str), &out_len, in, in_len))
ossl_raise(eCipherError, NULL);
assert(out_len < RSTRING_LEN(str));
rb_str_set_len(str, out_len);
@@ -523,17 +554,16 @@ ossl_cipher_set_auth_data(VALUE self, VALUE data)
{
EVP_CIPHER_CTX *ctx;
unsigned char *in;
- int in_len;
- int out_len;
+ long in_len, out_len;
StringValue(data);
in = (unsigned char *) RSTRING_PTR(data);
- in_len = RSTRING_LENINT(data);
+ in_len = RSTRING_LEN(data);
GetCipher(self, ctx);
- if (!EVP_CipherUpdate(ctx, NULL, &out_len, in, in_len))
+ if (!ossl_cipher_update_long(ctx, NULL, &out_len, in, in_len))
ossl_raise(eCipherError, "couldn't set additional authenticated data");
return data;