"Fossies" - the Fresh Open Source Software Archive

Member "mod_auth_gssapi-1.6.3/src/crypto.c" (14 Sep 2018, 6764 Bytes) of package /linux/www/apache_httpd_modules/mod_auth_gssapi-1.6.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "crypto.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.6.1_vs_1.6.2.

    1 /* Copyright (C) 2014 mod_auth_gssapi contributors - See COPYING for (C) terms */
    2 
    3 #include "config.h"
    4 #include <openssl/evp.h>
    5 #include <openssl/hmac.h>
    6 #include <openssl/rand.h>
    7 #include <stdbool.h>
    8 #include "crypto.h"
    9 
   10 #ifndef HAVE_HMAC_CTX_NEW
   11 HMAC_CTX *HMAC_CTX_new(void)
   12 {
   13     HMAC_CTX *ctx;
   14 
   15     ctx = OPENSSL_malloc(sizeof(HMAC_CTX));
   16     if (!ctx) return NULL;
   17 
   18     HMAC_CTX_init(ctx);
   19 
   20     return ctx;
   21 }
   22 
   23 void HMAC_CTX_free(HMAC_CTX *ctx)
   24 {
   25     if (ctx == NULL) return;
   26 
   27     HMAC_CTX_cleanup(ctx);
   28     OPENSSL_free(ctx);
   29 }
   30 #endif
   31 
   32 #ifndef HAVE_EVP_CIPHER_CTX_NEW
   33 EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void)
   34 {
   35     EVP_CIPHER_CTX *ctx;
   36 
   37     ctx = OPENSSL_malloc(sizeof(EVP_CIPHER_CTX));
   38     if (!ctx) return NULL;
   39 
   40     EVP_CIPHER_CTX_init(ctx);
   41 
   42     return ctx;
   43 }
   44 
   45 void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx)
   46 {
   47     if (ctx == NULL) return;
   48 
   49     EVP_CIPHER_CTX_cleanup(ctx);
   50     OPENSSL_free(ctx);
   51 }
   52 #endif
   53 
   54 struct seal_key {
   55     const EVP_CIPHER *cipher;
   56     const EVP_MD *md;
   57     unsigned char *ekey;
   58     unsigned char *hkey;
   59 };
   60 
   61 apr_status_t SEAL_KEY_CREATE(apr_pool_t *p, struct seal_key **skey,
   62                              struct databuf *keys)
   63 {
   64     struct seal_key *n;
   65     int keylen;
   66     int ret;
   67 
   68     n = apr_pcalloc(p, sizeof(*n));
   69     if (!n) return ENOMEM;
   70 
   71     n->cipher = EVP_aes_128_cbc();
   72     if (!n->cipher) {
   73         ret = EFAULT;
   74         goto done;
   75     }
   76 
   77     keylen = EVP_CIPHER_key_length(n->cipher);
   78 
   79     n->md = EVP_sha256();
   80     if (!n->md) {
   81         ret = EFAULT;
   82         goto done;
   83     }
   84 
   85     n->ekey = apr_palloc(p, keylen);
   86     if (!n->ekey) {
   87         ret = ENOMEM;
   88         goto done;
   89     }
   90 
   91     n->hkey = apr_palloc(p, keylen);
   92     if (!n->hkey) {
   93         ret = ENOMEM;
   94         goto done;
   95     }
   96 
   97     if (keys) {
   98         if (keys->length != (keylen * 2)) {
   99             ret = EINVAL;
  100             goto done;
  101         }
  102         memcpy(n->ekey, keys->value, keylen);
  103         memcpy(n->hkey, keys->value + keylen, keylen);
  104     } else {
  105         ret = apr_generate_random_bytes(n->ekey, keylen);
  106         if (ret != 0) {
  107             ret = EFAULT;
  108             goto done;
  109         }
  110 
  111         ret = apr_generate_random_bytes(n->hkey, keylen);
  112         if (ret != 0) {
  113             ret = EFAULT;
  114             goto done;
  115         }
  116     }
  117 
  118     ret = 0;
  119 done:
  120     if (ret == 0) {
  121         *skey = n;
  122     }
  123     return ret;
  124 }
  125 
  126 apr_status_t HMAC_BUFFER(struct seal_key *skey, struct databuf *buffer,
  127                          struct databuf *result)
  128 {
  129     HMAC_CTX *hmac_ctx;
  130     unsigned int len;
  131     int ret = 0;
  132 
  133     /* now MAC the buffer */
  134     hmac_ctx = HMAC_CTX_new();
  135     if (!hmac_ctx) goto done;
  136 
  137     ret = HMAC_Init_ex(hmac_ctx, skey->hkey,
  138                        EVP_CIPHER_key_length(skey->cipher), skey->md, NULL);
  139     if (ret == 0) goto done;
  140 
  141     ret = HMAC_Update(hmac_ctx, buffer->value, buffer->length);
  142     if (ret == 0) goto done;
  143 
  144     ret = HMAC_Final(hmac_ctx, result->value, &len);
  145 
  146 done:
  147     HMAC_CTX_free(hmac_ctx);
  148     if (ret == 0) return EFAULT;
  149 
  150     result->length = len;
  151     return 0;
  152 }
  153 
  154 apr_status_t SEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
  155                          struct databuf *plain, struct databuf *cipher)
  156 {
  157     int blksz = EVP_CIPHER_block_size(skey->cipher);
  158     apr_status_t err = EFAULT;
  159     EVP_CIPHER_CTX *ctx;
  160     uint8_t rbuf[blksz];
  161     struct databuf hmacbuf;
  162     int outlen, totlen;
  163     int ret;
  164 
  165     ctx = EVP_CIPHER_CTX_new();
  166 
  167     /* confounder to avoid exposing random numbers directly to clients
  168      * as IVs */
  169     ret = apr_generate_random_bytes(rbuf, sizeof(rbuf));
  170     if (ret != 0) goto done;
  171 
  172     if (cipher->length == 0) {
  173         /* add space for confounder and padding and MAC */
  174         cipher->length = (plain->length / blksz + 2) * blksz;
  175         cipher->value = apr_palloc(p, cipher->length + EVP_MD_size(skey->md));
  176         if (!cipher->value) {
  177             err = ENOMEM;
  178             goto done;
  179         }
  180     }
  181 
  182     ret = EVP_EncryptInit_ex(ctx, skey->cipher, NULL, skey->ekey, NULL);
  183     if (ret == 0) goto done;
  184     totlen = 0;
  185 
  186     outlen = cipher->length;
  187     ret = EVP_EncryptUpdate(ctx, cipher->value, &outlen, rbuf, sizeof(rbuf));
  188     if (ret == 0) goto done;
  189     totlen += outlen;
  190 
  191     outlen = cipher->length - totlen;
  192     ret = EVP_EncryptUpdate(ctx, &cipher->value[totlen], &outlen,
  193                             plain->value, plain->length);
  194     if (ret == 0) goto done;
  195     totlen += outlen;
  196 
  197     outlen = cipher->length - totlen;
  198     ret = EVP_EncryptFinal_ex(ctx, &cipher->value[totlen], &outlen);
  199     if (ret == 0) goto done;
  200     totlen += outlen;
  201 
  202     /* now MAC the buffer */
  203     cipher->length = totlen;
  204     hmacbuf.value = &cipher->value[totlen];
  205     ret = HMAC_BUFFER(skey, cipher, &hmacbuf);
  206     if (ret != 0) goto done;
  207 
  208     cipher->length += hmacbuf.length;
  209     err = 0;
  210 
  211 done:
  212     EVP_CIPHER_CTX_free(ctx);
  213     return err;
  214 }
  215 
  216 apr_status_t UNSEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
  217                            struct databuf *cipher, struct databuf *plain)
  218 {
  219     apr_status_t err = EFAULT;
  220     EVP_CIPHER_CTX *ctx = NULL;
  221     int blksz = EVP_CIPHER_block_size(skey->cipher);
  222     int md_size = EVP_MD_size(skey->md);
  223     unsigned char mac[md_size];
  224     struct databuf hmacbuf;
  225     int outlen, totlen;
  226     volatile bool equal = true;
  227     int ret, i;
  228 
  229     /* check MAC first */
  230     cipher->length -= md_size;
  231     hmacbuf.value = mac;
  232     ret = HMAC_BUFFER(skey, cipher, &hmacbuf);
  233     if (ret != 0) goto done;
  234 
  235     if (hmacbuf.length != md_size) goto done;
  236     for (i = 0; i < md_size; i++) {
  237         if (cipher->value[cipher->length + i] != mac[i]) equal = false;
  238         /* not breaking intentionally,
  239          * or we would allow an oracle attack */
  240     }
  241     if (!equal) goto done;
  242 
  243     ctx = EVP_CIPHER_CTX_new();
  244 
  245     if (plain->length == 0) {
  246         plain->length = cipher->length;
  247         plain->value = apr_palloc(p, plain->length);
  248         if (!plain->value) {
  249             err = ENOMEM;
  250             goto done;
  251         }
  252     }
  253 
  254     ret = EVP_DecryptInit_ex(ctx, skey->cipher, NULL, skey->ekey, NULL);
  255     if (ret == 0) goto done;
  256 
  257     totlen = 0;
  258     outlen = plain->length;
  259     ret = EVP_DecryptUpdate(ctx, plain->value, &outlen,
  260                             cipher->value, cipher->length);
  261     if (ret == 0) goto done;
  262 
  263     totlen += outlen;
  264     outlen = plain->length - totlen;
  265     ret = EVP_DecryptFinal_ex(ctx, plain->value, &outlen);
  266     if (ret == 0) goto done;
  267 
  268     totlen += outlen;
  269     /* now remove the confounder */
  270     totlen -= blksz;
  271     memmove(plain->value, plain->value + blksz, totlen);
  272 
  273     plain->length = totlen;
  274     err = 0;
  275 
  276 done:
  277     EVP_CIPHER_CTX_free(ctx);
  278     return err;
  279 }
  280 
  281 int get_mac_size(struct seal_key *skey)
  282 {
  283     if (skey) {
  284         return EVP_MD_size(skey->md);
  285     } else {
  286         return 0;
  287     }
  288 }