Home | History | Annotate | Line # | Download | only in ServiceRegistration
hmac-openssl.c revision 1.1
      1 /* hmac-openssl.c
      2  *
      3  * Copyright (c) 2019 Apple Computer, Inc. All rights reserved.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  *
     17  * Hashed message authentication code functions using OpenSSL.
     18  */
     19 
     20 #include <stdio.h>
     21 #include <arpa/inet.h>
     22 #include <string.h>
     23 #include <stdlib.h>
     24 #include <unistd.h>
     25 #include <fcntl.h>
     26 #include <errno.h>
     27 
     28 #include "srp.h"
     29 #include "dns-msg.h"
     30 #define SRP_CRYPTO_OPENSSL_INTERNAL
     31 #include "srp-crypto.h"
     32 
     33 // Function to generate a signature given some data and a private key
     34 void
     35 srp_hmac_iov(hmac_key_t *key, uint8_t *output, size_t max, struct iovec *iov, int count)
     36 {
     37     int status;
     38     char errbuf[64];
     39     uint8_t kipad[SRP_SHA256_BLOCK_SIZE], kopad[SRP_SHA256_BLOCK_SIZE], intermediate[SRP_SHA256_HASH_SIZE];
     40     EVP_MD_CTX inner, outer;
     41     const EVP_MD md;
     42     int i;
     43 
     44     if (key->algorithm != SRP_HMAC_TYPE_SHA256) {
     45         ERROR("srp_hmac_iov: unsupported HMAC hash algorithm: %d", key->algorithm);
     46         return;
     47     }
     48     if (max < SRP_SHA256_HASH_SIZE) {
     49         ERROR("srp_hmac_iov: not enough space in output buffer (%lu) for hash (%d).",
     50               (unsigned long)max, SRP_SHA256_HASH_SIZE);
     51         return;
     52     }
     53 
     54     md = EVP_sha256();
     55     EVP_MD_CTX_INIT(&inner);
     56 
     57     // If the key is longer than the block size, hash it and use the digest as the key.
     58     if (key->length > SRP_SHA256_BLOCK_SIZE) {
     59         if ((status = EVP_DigestInit(&inner, md)) != 0) {
     60             ERROR("srp_hmac_iov failed to initialize key digest");
     61             return;
     62         }
     63         // Compute H(K)
     64         if ((status = EVP_DigestUpdate(&inner, key, key->length)) != 0) {
     65             ERROR("srp_hmac_iov failed to hash key");
     66             return;
     67         }
     68         if ((status = EVP_DigestFinal(&inner, intermediate, SRP_SHA256_HASH_SIZE)) != 0) {
     69             ERROR("srp_hmac_iov failed to digest key");
     70             return;
     71         }
     72         EVP_MD_CTX_INIT(&inner);
     73     }
     74 
     75     // Compute key ^ kipad and key ^ kopad
     76     for (i = 0; i < SRP_SHA256_BLOCK_SIZE; i++) {
     77         uint8_t byte = i >= key->length ? 0 : key->secret[i];
     78         kipad[i] = byte ^ 0x36;
     79         kopad[i] = byte ^ 0x5c;
     80     }
     81 
     82     if ((status = EVP_DigestInit(&inner, md)) != 0) {
     83         ERROR("srp_hmac_iov failed to initialize inner digest");
     84         return;
     85     }
     86     // Compute H(K xor ipad, text)
     87     if ((status = EVP_DigestUpdate(&inner, kipad, SRP_SHA256_BLOCK_SIZE)) != 0) {
     88         ERROR("srp_hmac_iov failed to hash ipad to inner digest");
     89         return;
     90     }
     91     for (i = 0; i < count; i++) {
     92         if ((status = EVP_DigestUpdate(&inner, iov[i].iov_base, iov[i].iov_len)) != 0) {
     93             ERROR("srp_hmac_iov failed to hash chunk %d to inner digest", i);
     94             return;
     95         }
     96     }
     97     if ((status = EVP_DigestFinal(&inner, intermediate, SRP_SHA256_HASH_SIZE)) != 0) {
     98         ERROR("srp_hmac_iov failed to hash ipad to inner digest");
     99         return;
    100     }
    101 
    102     // Compute H(K xor opad, H(K xor ipad, text))
    103     EVP_MD_CTX_INIT(&outer);
    104     if ((status = EVP_DigestInit(&outer, md)) != 0) {
    105         ERROR("srp_hmac_iov failed to initialize outer digest");
    106         return;
    107     }
    108     if ((status = EVP_DigestUpdate(&outer, kopad, SRP_SHA256_BLOCK_SIZE)) != 0) {
    109         ERROR("srp_hmac_iov failed to hash outer pad");
    110         return;
    111         goto kablooie;
    112     }
    113     if ((status = EVP_DigestUpdate(&outer, intermediate, SRP_SHA256_HASH_SIZE)) != 0) {
    114         ERROR("srp_hmac_iov failed to hash outer digest");
    115         return;
    116         goto kablooie;
    117     }
    118     if ((status = EVP_DigestFinal(&outer, output, max)) != 0) {
    119         ERROR("srp_hmac_iov failed to hash outer outer pad with inner digest");
    120         return;
    121     }
    122     // Bob's your uncle...
    123 }
    124 
    125 int
    126 srp_base64_parse(char *src, size_t *len_ret, uint8_t *buf, size_t buflen)
    127 {
    128     size_t slen = strlen(src);
    129     int ret = mbedtls_base64_decode(buf, buflen, len_ret, (const unsigned char *)src, slen);
    130     if (ret == MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) {
    131         return ENOBUFS;
    132     } else if (ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER) {
    133         return EILSEQ;
    134     } else if (ret < 0) {
    135         return EINVAL;
    136     }
    137     return 0;
    138 }
    139 
    140 // Local Variables:
    141 // mode: C
    142 // tab-width: 4
    143 // c-file-style: "bsd"
    144 // c-basic-offset: 4
    145 // fill-column: 108
    146 // indent-tabs-mode: nil
    147 // End:
    148