aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2016-05-21 20:52:54 +0900
committerKazuki Yamaguchi <k@rhe.jp>2016-05-21 20:52:54 +0900
commit5a85aaa6148955e10da433351589d10a5458a3c5 (patch)
tree379b84da2ea39869c2ed881cdac9fd8c819043da
parent021ba2ce0a9b3cdc08e008fa4196bf4ab52f54e7 (diff)
downloadruby-topic/openssl-ccm.tar.gz
-rw-r--r--ext/openssl/ossl_cipher.c89
1 files changed, 53 insertions, 36 deletions
diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c
index 09b021d..bbb738c 100644
--- a/ext/openssl/ossl_cipher.c
+++ b/ext/openssl/ossl_cipher.c
@@ -29,6 +29,15 @@
GetCipher((obj), (ctx)); \
} while (0)
+
+#define ossl_is_gcm(nid) ((nid) == NID_aes_128_gcm || \
+ (nid) == NID_aes_192_gcm || \
+ (nid) == NID_aes_256_gcm)
+
+#define ossl_is_ccm(nid) ((nid) == NID_aes_128_ccm || \
+ (nid) == NID_aes_192_ccm || \
+ (nid) == NID_aes_256_ccm)
+
/*
* Classes
*/
@@ -512,12 +521,32 @@ static VALUE
ossl_cipher_set_iv(VALUE self, VALUE iv)
{
EVP_CIPHER_CTX *ctx;
+ int iv_len, new_len;
StringValue(iv);
GetCipher(self, ctx);
- if (RSTRING_LEN(iv) < EVP_CIPHER_CTX_iv_length(ctx))
- ossl_raise(eCipherError, "iv length too short");
+ iv_len = EVP_CIPHER_CTX_iv_length(ctx);
+ new_len = RSTRING_LENINT(iv);
+ if (new_len != iv_len) {
+ int nid = EVP_CIPHER_CTX_nid(ctx);
+
+ /* if the cipher is GCM/CCM mode, the IV length can be changed */
+ if (ossl_is_gcm(nid)) {
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, new_len, NULL))
+ ossl_raise(eCipherError, NULL);
+ }
+ else if (ossl_is_ccm(nid)) {
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, new_len, NULL))
+ ossl_raise(eCipherError, NULL);
+ }
+ else {
+ if (new_len < iv_len)
+ ossl_raise(eCipherError, "iv length too short");
+ else
+ rb_warn("iv too long; truncated to %d bytes", iv_len);
+ }
+ }
if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, (unsigned char *)RSTRING_PTR(iv), -1) != 1)
ossl_raise(eCipherError, NULL);
@@ -564,29 +593,9 @@ ossl_cipher_set_auth_data(VALUE self, VALUE data)
return data;
}
-#define ossl_is_gcm(nid) (nid) == NID_aes_128_gcm || \
- (nid) == NID_aes_192_gcm || \
- (nid) == NID_aes_256_gcm
-
-static VALUE
-ossl_get_gcm_auth_tag(EVP_CIPHER_CTX *ctx, int len)
-{
- unsigned char *tag;
- VALUE ret;
-
- tag = ALLOC_N(unsigned char, len);
-
- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, len, tag))
- ossl_raise(eCipherError, "retrieving the authentication tag failed");
-
- ret = rb_str_new((const char *) tag, len);
- xfree(tag);
- return ret;
-}
-
/*
* call-seq:
- * cipher.auth_tag([ tag_len ] -> string
+ * cipher.auth_tag([tag_len]) -> string
*
* Gets the authentication tag generated by Authenticated Encryption Cipher
* modes (GCM for example). This tag may be stored along with the ciphertext,
@@ -601,7 +610,7 @@ ossl_get_gcm_auth_tag(EVP_CIPHER_CTX *ctx, int len)
static VALUE
ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self)
{
- VALUE vtag_len;
+ VALUE vtag_len, ret;
EVP_CIPHER_CTX *ctx;
int nid, tag_len;
@@ -614,19 +623,21 @@ ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self)
GetCipher(self, ctx);
nid = EVP_CIPHER_CTX_nid(ctx);
+ ret = rb_str_new(NULL, tag_len);
+
if (ossl_is_gcm(nid)) {
- return ossl_get_gcm_auth_tag(ctx, tag_len);
- } else {
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, tag_len, RSTRING_PTR(ret)))
+ ossl_raise(eCipherError, "retrieving the authentication tag failed");
+ }
+ else if (ossl_is_ccm(nid)) {
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, tag_len, RSTRING_PTR(ret)))
+ ossl_raise(eCipherError, "retrieving the authentication tag failed");
+ }
+ else {
ossl_raise(eCipherError, "authentication tag not supported by this cipher");
- return Qnil; /* dummy */
}
-}
-static inline void
-ossl_set_gcm_auth_tag(EVP_CIPHER_CTX *ctx, unsigned char *tag, int tag_len)
-{
- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_len, tag))
- ossl_raise(eCipherError, "unable to set GCM tag");
+ return ret;
}
/*
@@ -657,8 +668,14 @@ ossl_cipher_set_auth_tag(VALUE self, VALUE vtag)
nid = EVP_CIPHER_CTX_nid(ctx);
if (ossl_is_gcm(nid)) {
- ossl_set_gcm_auth_tag(ctx, tag, tag_len);
- } else {
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_len, tag))
+ ossl_raise(eCipherError, "unable to set GCM tag");
+ }
+ else if (ossl_is_ccm(nid)) {
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag_len, tag))
+ ossl_raise(eCipherError, "unable to set CCM tag");
+ }
+ else {
ossl_raise(eCipherError, "authentication tag not supported by this cipher");
}
@@ -681,7 +698,7 @@ ossl_cipher_is_authenticated(VALUE self)
GetCipher(self, ctx);
nid = EVP_CIPHER_CTX_nid(ctx);
- if (ossl_is_gcm(nid)) {
+ if (ossl_is_gcm(nid) || ossl_is_ccm(nid)) {
return Qtrue;
} else {
return Qfalse;