Fix incorrect free() usage
[mod_auth_gssapi.git] / src / crypto.c
index 9be58e5..1983a55 100644 (file)
@@ -13,66 +13,106 @@ struct seal_key {
     unsigned char *hkey;
 };
 
-apr_status_t SEAL_KEY_CREATE(struct seal_key **skey)
+apr_status_t SEAL_KEY_CREATE(apr_pool_t *p, struct seal_key **skey,
+                             struct databuf *keys)
 {
     struct seal_key *n;
+    int keylen;
     int ret;
 
-    n = calloc(1, sizeof(*n));
+    n = apr_pcalloc(p, sizeof(*n));
     if (!n) return ENOMEM;
 
     n->cipher = EVP_aes_128_cbc();
     if (!n->cipher) {
-        free(n);
-        return EFAULT;
+        ret = EFAULT;
+        goto done;
     }
 
+    keylen = n->cipher->key_len;
+
     n->md = EVP_sha256();
     if (!n->md) {
-        free(n);
-        return EFAULT;
+        ret = EFAULT;
+        goto done;
     }
 
-    n->ekey = malloc(n->cipher->key_len);
+    n->ekey = apr_palloc(p, keylen);
     if (!n->ekey) {
-        free(n);
-        return ENOMEM;
+        ret = ENOMEM;
+        goto done;
     }
 
-    n->hkey = malloc(n->cipher->key_len);
+    n->hkey = apr_palloc(p, keylen);
     if (!n->hkey) {
-        free(n);
-        return ENOMEM;
+        ret = ENOMEM;
+        goto done;
     }
 
-    ret = RAND_bytes(n->ekey, n->cipher->key_len);
-    if (ret == 0) {
-        free(n->ekey);
-        free(n->hkey);
-        free(n);
-        return EFAULT;
+    if (keys) {
+        if (keys->length != (keylen * 2)) {
+            ret = EINVAL;
+            goto done;
+        }
+        memcpy(n->ekey, keys->value, keylen);
+        memcpy(n->hkey, keys->value + keylen, keylen);
+    } else {
+        ret = apr_generate_random_bytes(n->ekey, keylen);
+        if (ret != 0) {
+            ret = EFAULT;
+            goto done;
+        }
+
+        ret = apr_generate_random_bytes(n->hkey, keylen);
+        if (ret != 0) {
+            ret = EFAULT;
+            goto done;
+        }
     }
 
-    ret = RAND_bytes(n->hkey, n->cipher->key_len);
+    ret = 0;
+done:
     if (ret == 0) {
-        free(n->ekey);
-        free(n->hkey);
-        free(n);
-        return EFAULT;
+        *skey = n;
     }
+    return ret;
+}
+
+apr_status_t HMAC_BUFFER(struct seal_key *skey, struct databuf *buffer,
+                         struct databuf *result)
+{
+    HMAC_CTX hmac_ctx = { 0 };
+    unsigned int len;
+    int ret;
+
+    /* now MAC the buffer */
+    HMAC_CTX_init(&hmac_ctx);
+
+    ret = HMAC_Init_ex(&hmac_ctx, skey->hkey,
+                       skey->cipher->key_len, skey->md, NULL);
+    if (ret == 0) goto done;
 
-    *skey = n;
+    ret = HMAC_Update(&hmac_ctx, buffer->value, buffer->length);
+    if (ret == 0) goto done;
+
+    ret = HMAC_Final(&hmac_ctx, result->value, &len);
+
+done:
+    HMAC_CTX_cleanup(&hmac_ctx);
+    if (ret == 0) return EFAULT;
+
+    result->length = len;
     return 0;
 }
 
 apr_status_t SEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
                          struct databuf *plain, struct databuf *cipher)
 {
+    int blksz = skey->cipher->block_size;
     apr_status_t err = EFAULT;
     EVP_CIPHER_CTX ctx = { 0 };
-    HMAC_CTX hmac_ctx = { 0 };
-    uint8_t rbuf[16];
-    unsigned int len;
+    uint8_t rbuf[blksz];
+    struct databuf hmacbuf;
     int outlen, totlen;
     int ret;
 
@@ -80,12 +120,12 @@ apr_status_t SEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
 
     /* confounder to avoid exposing random numbers directly to clients
      * as IVs */
-    ret = RAND_bytes(rbuf, 16);
-    if (ret == 0) goto done;
+    ret = apr_generate_random_bytes(rbuf, sizeof(rbuf));
+    if (ret != 0) goto done;
 
     if (cipher->length == 0) {
         /* add space for confounder and padding and MAC */
-        cipher->length = (plain->length / 16 + 2) * 16;
+        cipher->length = (plain->length / blksz + 2) * blksz;
         cipher->value = apr_palloc(p, cipher->length + skey->md->md_size);
         if (!cipher->value) {
             err = ENOMEM;
@@ -98,7 +138,7 @@ apr_status_t SEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
     totlen = 0;
 
     outlen = cipher->length;
-    ret = EVP_EncryptUpdate(&ctx, cipher->value, &outlen, rbuf, 16);
+    ret = EVP_EncryptUpdate(&ctx, cipher->value, &outlen, rbuf, sizeof(rbuf));
     if (ret == 0) goto done;
     totlen += outlen;
 
@@ -114,24 +154,16 @@ apr_status_t SEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
     totlen += outlen;
 
     /* now MAC the buffer */
-    HMAC_CTX_init(&hmac_ctx);
-
-    ret = HMAC_Init_ex(&hmac_ctx, skey->hkey,
-                       skey->cipher->key_len, skey->md, NULL);
-    if (ret == 0) goto done;
+    cipher->length = totlen;
+    hmacbuf.value = &cipher->value[totlen];
+    ret = HMAC_BUFFER(skey, cipher, &hmacbuf);
+    if (ret != 0) goto done;
 
-    ret = HMAC_Update(&hmac_ctx, cipher->value, totlen);
-    if (ret == 0) goto done;
-
-    ret = HMAC_Final(&hmac_ctx, &cipher->value[totlen], &len);
-    if (ret == 0) goto done;
-
-    cipher->length = totlen + len;
+    cipher->length += hmacbuf.length;
     err = 0;
 
 done:
     EVP_CIPHER_CTX_cleanup(&ctx);
-    HMAC_CTX_cleanup(&hmac_ctx);
     return err;
 }
 
@@ -140,29 +172,19 @@ apr_status_t UNSEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
 {
     apr_status_t err = EFAULT;
     EVP_CIPHER_CTX ctx = { 0 };
-    HMAC_CTX hmac_ctx = { 0 };
     unsigned char mac[skey->md->md_size];
-    unsigned int len;
+    struct databuf hmacbuf;
     int outlen, totlen;
     volatile bool equal = true;
     int ret, i;
 
     /* check MAC first */
-    HMAC_CTX_init(&hmac_ctx);
-
-    ret = HMAC_Init_ex(&hmac_ctx, skey->hkey,
-                       skey->cipher->key_len, skey->md, NULL);
-    if (ret == 0) goto done;
-
     cipher->length -= skey->md->md_size;
+    hmacbuf.value = mac;
+    ret = HMAC_BUFFER(skey, cipher, &hmacbuf);
+    if (ret != 0) goto done;
 
-    ret = HMAC_Update(&hmac_ctx, cipher->value, cipher->length);
-    if (ret == 0) goto done;
-
-    ret = HMAC_Final(&hmac_ctx, mac, &len);
-    if (ret == 0) goto done;
-
-    if (len != skey->md->md_size) goto done;
+    if (hmacbuf.length != skey->md->md_size) goto done;
     for (i = 0; i < skey->md->md_size; i++) {
         if (cipher->value[cipher->length + i] != mac[i]) equal = false;
         /* not breaking intentionally,
@@ -197,14 +219,22 @@ apr_status_t UNSEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
 
     totlen += outlen;
     /* now remove the confounder */
-    totlen -= 16;
-    memmove(plain->value, plain->value + 16, totlen);
+    totlen -= skey->cipher->block_size;
+    memmove(plain->value, plain->value + skey->cipher->block_size, totlen);
 
     plain->length = totlen;
     err = 0;
 
 done:
     EVP_CIPHER_CTX_cleanup(&ctx);
-    HMAC_CTX_cleanup(&hmac_ctx);
     return err;
 }
+
+int get_mac_size(struct seal_key *skey)
+{
+    if (skey) {
+        return skey->md->md_size;
+    } else {
+        return 0;
+    }
+}