Fix AES GCM IV setting in KeyProvider
[platform/core/security/key-manager.git] / src / manager / service / key-provider.cpp
index cf15ed8..2bbe45f 100644 (file)
@@ -37,6 +37,7 @@ namespace {
 constexpr int PBKDF2_ITERATIONS = 4096;
 constexpr uint32_t KEYCOMPONENT_VERSION = 2;
 constexpr int OPENSSL_ENGINE_ERROR = -4;
+constexpr int AUTHENTICATION_ERROR = -5;
 
 template<typename T>
 RawBuffer toRawBuffer(const T &data)
@@ -72,10 +73,10 @@ int encryptAes256Gcm(const unsigned char *plaintext,
        if (!EVP_EncryptInit_ex(ctx.get(), EVP_aes_256_gcm(), NULL, NULL, NULL))
                return OPENSSL_ENGINE_ERROR;
 
-       if (!EVP_EncryptInit_ex(ctx.get(), NULL, NULL, key, iv))
+       if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, MAX_IV_SIZE, NULL))
                return OPENSSL_ENGINE_ERROR;
 
-       if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, MAX_IV_SIZE, NULL))
+       if (!EVP_EncryptInit_ex(ctx.get(), NULL, NULL, key, iv))
                return OPENSSL_ENGINE_ERROR;
 
        if (!EVP_EncryptUpdate(ctx.get(), ciphertext, &len, plaintext, plaintext_len))
@@ -98,40 +99,48 @@ int decryptAes256Gcm(const unsigned char *ciphertext,
                      int ciphertext_len, unsigned char *tag, const unsigned char *key,
                      const unsigned char *iv, unsigned char *plaintext)
 {
-       int len;
-       int plaintext_len;
-       int ret;
+       auto decrypt = [&](size_t iv_len){
+               int len;
+               int plaintext_len;
+               int ret;
 
-       auto ctx = uptr<EVP_CIPHER_CTX_free>(EVP_CIPHER_CTX_new());
-       if (!ctx)
-               return OPENSSL_ENGINE_ERROR;
+               auto ctx = uptr<EVP_CIPHER_CTX_free>(EVP_CIPHER_CTX_new());
+               if (!ctx)
+                       return OPENSSL_ENGINE_ERROR;
 
-       if (!EVP_DecryptInit_ex(ctx.get(), EVP_aes_256_gcm(), NULL, NULL, NULL))
-               return OPENSSL_ENGINE_ERROR;
+               if (!EVP_DecryptInit_ex(ctx.get(), EVP_aes_256_gcm(), NULL, NULL, NULL))
+                       return OPENSSL_ENGINE_ERROR;
 
-       if (!EVP_DecryptInit_ex(ctx.get(), NULL, NULL, key, iv))
-               return OPENSSL_ENGINE_ERROR;
+               if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
+                       return OPENSSL_ENGINE_ERROR;
 
-       if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, MAX_IV_SIZE, NULL))
-               return OPENSSL_ENGINE_ERROR;
+               if (!EVP_DecryptInit_ex(ctx.get(), NULL, NULL, key, iv))
+                       return OPENSSL_ENGINE_ERROR;
 
-       if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, MAX_IV_SIZE, tag))
-               return OPENSSL_ENGINE_ERROR;
+               if (!EVP_DecryptUpdate(ctx.get(), plaintext, &len, ciphertext, ciphertext_len))
+                       return OPENSSL_ENGINE_ERROR;
 
-       if (!EVP_DecryptUpdate(ctx.get(), plaintext, &len, ciphertext, ciphertext_len))
-               return OPENSSL_ENGINE_ERROR;
+               plaintext_len = len;
 
-       plaintext_len = len;
+               if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, MAX_IV_SIZE, tag))
+                       return OPENSSL_ENGINE_ERROR;
 
-       if (!(ret = EVP_DecryptFinal_ex(ctx.get(), plaintext + len, &len)))
-               return OPENSSL_ENGINE_ERROR;
+               if (!(ret = EVP_DecryptFinal_ex(ctx.get(), plaintext + len, &len)))
+                       return AUTHENTICATION_ERROR;
 
-       if (ret > 0) {
-               plaintext_len += len;
-               return plaintext_len;
-       } else {
-               return -1;
-       }
+               if (ret > 0) {
+                       plaintext_len += len;
+                       return plaintext_len;
+               } else {
+                       return -1;
+               }
+       };
+
+       auto ret = decrypt(MAX_IV_SIZE);
+       if (ret == AUTHENTICATION_ERROR)
+               ret = decrypt(12); // retry with truncated IV
+
+       return ret;
 }
 
 typedef std::array<uint8_t, MAX_KEY_SIZE> KeyData;