/* $OpenBSD: crypto.c,v 1.19 2015/10/31 19:28:19 naddy Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <sys/param.h> /* roundup */ #include <sys/queue.h> #include <sys/socket.h> #include <sys/uio.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <event.h> #include <openssl/hmac.h> #include <openssl/evp.h> #include <openssl/sha.h> #include <openssl/md5.h> #include <openssl/x509.h> #include <openssl/rsa.h> #include "iked.h" #include "ikev2.h" /* RFC 7427, A.1 */ static const uint8_t sha256WithRSAEncryption[] = { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00 }; static const uint8_t sha384WithRSAEncryption[] = { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00 }; static const uint8_t sha512WithRSAEncryption[] = { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00 }; struct { uint8_t sc_len; const uint8_t *sc_oid; const EVP_MD *(*sc_md)(void); } schemes[] = { { sizeof(sha256WithRSAEncryption), sha256WithRSAEncryption, EVP_sha256 }, { sizeof(sha384WithRSAEncryption), sha384WithRSAEncryption, EVP_sha384 }, { sizeof(sha512WithRSAEncryption), sha512WithRSAEncryption, EVP_sha512 }, }; int _dsa_verify_init(struct iked_dsa *, const uint8_t *, size_t); size_t _dsa_verify_offset(struct iked_dsa *, uint8_t *); int _dsa_sign_encode(struct iked_dsa *, uint8_t *, size_t *); struct iked_hash * hash_new(uint8_t type, uint16_t id) { struct iked_hash *hash; const EVP_MD *md = NULL; HMAC_CTX *ctx = NULL; int length = 0, fixedkey = 0, trunc = 0; switch (type) { case IKEV2_XFORMTYPE_PRF: switch (id) { case IKEV2_XFORMPRF_HMAC_MD5: md = EVP_md5(); length = MD5_DIGEST_LENGTH; break; case IKEV2_XFORMPRF_HMAC_SHA1: md = EVP_sha1(); length = SHA_DIGEST_LENGTH; break; case IKEV2_XFORMPRF_HMAC_SHA2_256: md = EVP_sha256(); length = SHA256_DIGEST_LENGTH; break; case IKEV2_XFORMPRF_HMAC_SHA2_384: md = EVP_sha384(); length = SHA384_DIGEST_LENGTH; break; case IKEV2_XFORMPRF_HMAC_SHA2_512: md = EVP_sha512(); length = SHA512_DIGEST_LENGTH; break; case IKEV2_XFORMPRF_AES128_XCBC: fixedkey = 128 / 8; length = fixedkey; /* FALLTHROUGH */ case IKEV2_XFORMPRF_HMAC_TIGER: case IKEV2_XFORMPRF_AES128_CMAC: default: log_debug("%s: prf %s not supported", __func__, print_map(id, ikev2_xformprf_map)); break; } break; case IKEV2_XFORMTYPE_INTEGR: switch (id) { case IKEV2_XFORMAUTH_HMAC_MD5_96: md = EVP_md5(); length = MD5_DIGEST_LENGTH; trunc = 12; break; case IKEV2_XFORMAUTH_HMAC_SHA1_96: md = EVP_sha1(); length = SHA_DIGEST_LENGTH; trunc = 12; break; case IKEV2_XFORMAUTH_HMAC_SHA2_256_128: md = EVP_sha256(); length = SHA256_DIGEST_LENGTH; trunc = 16; break; case IKEV2_XFORMAUTH_HMAC_SHA2_384_192: md = EVP_sha384(); length = SHA384_DIGEST_LENGTH; trunc = 24; break; case IKEV2_XFORMAUTH_HMAC_SHA2_512_256: md = EVP_sha512(); length = SHA512_DIGEST_LENGTH; trunc = 32; break; case IKEV2_XFORMAUTH_NONE: case IKEV2_XFORMAUTH_DES_MAC: case IKEV2_XFORMAUTH_KPDK_MD5: case IKEV2_XFORMAUTH_AES_XCBC_96: case IKEV2_XFORMAUTH_HMAC_MD5_128: case IKEV2_XFORMAUTH_HMAC_SHA1_160: case IKEV2_XFORMAUTH_AES_CMAC_96: case IKEV2_XFORMAUTH_AES_128_GMAC: case IKEV2_XFORMAUTH_AES_192_GMAC: case IKEV2_XFORMAUTH_AES_256_GMAC: default: log_debug("%s: auth %s not supported", __func__, print_map(id, ikev2_xformauth_map)); break; } break; default: log_debug("%s: hash type %s not supported", __func__, print_map(id, ikev2_xformtype_map)); break; } if (md == NULL) return (NULL); if ((hash = calloc(1, sizeof(*hash))) == NULL) { log_debug("%s: alloc hash", __func__); return (NULL); } hash->hash_type = type; hash->hash_id = id; hash->hash_priv = md; hash->hash_ctx = NULL; hash->hash_trunc = trunc; hash->hash_length = length; hash->hash_fixedkey = fixedkey; if ((ctx = calloc(1, sizeof(*ctx))) == NULL) { log_debug("%s: alloc hash ctx", __func__); hash_free(hash); return (NULL); } HMAC_CTX_init(ctx); hash->hash_ctx = ctx; return (hash); } struct ibuf * hash_setkey(struct iked_hash *hash, void *key, size_t keylen) { ibuf_release(hash->hash_key); if ((hash->hash_key = ibuf_new(key, keylen)) == NULL) { log_debug("%s: alloc hash key", __func__); return (NULL); } return (hash->hash_key); } void hash_free(struct iked_hash *hash) { if (hash == NULL) return; if (hash->hash_ctx != NULL) { HMAC_CTX_cleanup(hash->hash_ctx); free(hash->hash_ctx); } ibuf_release(hash->hash_key); free(hash); } void hash_init(struct iked_hash *hash) { HMAC_Init_ex(hash->hash_ctx, hash->hash_key->buf, ibuf_length(hash->hash_key), hash->hash_priv, NULL); } void hash_update(struct iked_hash *hash, void *buf, size_t len) { HMAC_Update(hash->hash_ctx, buf, len); } void hash_final(struct iked_hash *hash, void *buf, size_t *len) { unsigned int length = 0; HMAC_Final(hash->hash_ctx, buf, &length); *len = (size_t)length; /* Truncate the result if required by the alg */ if (hash->hash_trunc && *len > hash->hash_trunc) *len = hash->hash_trunc; } size_t hash_length(struct iked_hash *hash) { if (hash->hash_trunc) return (hash->hash_trunc); return (hash->hash_length); } size_t hash_keylength(struct iked_hash *hash) { return (hash->hash_length); } struct iked_cipher * cipher_new(uint8_t type, uint16_t id, uint16_t id_length) { struct iked_cipher *encr; const EVP_CIPHER *cipher = NULL; EVP_CIPHER_CTX *ctx = NULL; int length = 0, fixedkey = 0, ivlength = 0; switch (type) { case IKEV2_XFORMTYPE_ENCR: switch (id) { case IKEV2_XFORMENCR_3DES: cipher = EVP_des_ede3_cbc(); length = EVP_CIPHER_block_size(cipher); fixedkey = EVP_CIPHER_key_length(cipher); ivlength = EVP_CIPHER_iv_length(cipher); break; case IKEV2_XFORMENCR_AES_CBC: switch (id_length) { case 128: cipher = EVP_aes_128_cbc(); break; case 192: cipher = EVP_aes_192_cbc(); break; case 256: cipher = EVP_aes_256_cbc(); break; default: log_debug("%s: invalid key length %d" " for cipher %s", __func__, id_length, print_map(id, ikev2_xformencr_map)); break; } if (cipher == NULL) break; length = EVP_CIPHER_block_size(cipher); ivlength = EVP_CIPHER_iv_length(cipher); fixedkey = EVP_CIPHER_key_length(cipher); break; case IKEV2_XFORMENCR_DES_IV64: case IKEV2_XFORMENCR_DES: case IKEV2_XFORMENCR_RC5: case IKEV2_XFORMENCR_IDEA: case IKEV2_XFORMENCR_CAST: case IKEV2_XFORMENCR_BLOWFISH: case IKEV2_XFORMENCR_3IDEA: case IKEV2_XFORMENCR_DES_IV32: case IKEV2_XFORMENCR_NULL: case IKEV2_XFORMENCR_AES_CTR: /* FALLTHROUGH */ default: log_debug("%s: cipher %s not supported", __func__, print_map(id, ikev2_xformencr_map)); cipher = NULL; break; } break; default: log_debug("%s: cipher type %s not supported", __func__, print_map(id, ikev2_xformtype_map)); break; } if (cipher == NULL) return (NULL); if ((encr = calloc(1, sizeof(*encr))) == NULL) { log_debug("%s: alloc cipher", __func__); return (NULL); } encr->encr_id = id; encr->encr_priv = cipher; encr->encr_ctx = NULL; encr->encr_length = length; encr->encr_fixedkey = fixedkey; encr->encr_ivlength = ivlength ? ivlength : length; if ((ctx = calloc(1, sizeof(*ctx))) == NULL) { log_debug("%s: alloc cipher ctx", __func__); cipher_free(encr); return (NULL); } EVP_CIPHER_CTX_init(ctx); encr->encr_ctx = ctx; return (encr); } struct ibuf * cipher_setkey(struct iked_cipher *encr, void *key, size_t keylen) { ibuf_release(encr->encr_key); if ((encr->encr_key = ibuf_new(key, keylen)) == NULL) { log_debug("%s: alloc cipher key", __func__); return (NULL); } return (encr->encr_key); } struct ibuf * cipher_setiv(struct iked_cipher *encr, void *iv, size_t len) { ibuf_release(encr->encr_iv); if (iv != NULL) { if (len < encr->encr_ivlength) { log_debug("%s: invalid IV length %zu", __func__, len); return (NULL); } encr->encr_iv = ibuf_new(iv, encr->encr_ivlength); } else { /* Get new random IV */ encr->encr_iv = ibuf_random(encr->encr_ivlength); } if (encr->encr_iv == NULL) { log_debug("%s: failed to set IV", __func__); return (NULL); } return (encr->encr_iv); } void cipher_free(struct iked_cipher *encr) { if (encr == NULL) return; if (encr->encr_ctx != NULL) { EVP_CIPHER_CTX_cleanup(encr->encr_ctx); free(encr->encr_ctx); } ibuf_release(encr->encr_key); free(encr); } void cipher_init(struct iked_cipher *encr, int enc) { EVP_CipherInit_ex(encr->encr_ctx, encr->encr_priv, NULL, ibuf_data(encr->encr_key), ibuf_data(encr->encr_iv), enc); EVP_CIPHER_CTX_set_padding(encr->encr_ctx, 0); } void cipher_init_encrypt(struct iked_cipher *encr) { cipher_init(encr, 1); } void cipher_init_decrypt(struct iked_cipher *encr) { cipher_init(encr, 0); } void cipher_update(struct iked_cipher *encr, void *in, size_t inlen, void *out, size_t *outlen) { int olen; olen = 0; if (!EVP_CipherUpdate(encr->encr_ctx, out, &olen, in, inlen)) { ca_sslerror(__func__); *outlen = 0; return; } *outlen = (size_t)olen; } void cipher_final(struct iked_cipher *encr, void *out, size_t *outlen) { int olen; olen = 0; if (!EVP_CipherFinal_ex(encr->encr_ctx, out, &olen)) { ca_sslerror(__func__); *outlen = 0; return; } *outlen = (size_t)olen; } size_t cipher_length(struct iked_cipher *encr) { return (encr->encr_length); } size_t cipher_keylength(struct iked_cipher *encr) { if (encr->encr_fixedkey) return (encr->encr_fixedkey); /* Might return zero */ return (ibuf_length(encr->encr_key)); } size_t cipher_ivlength(struct iked_cipher *encr) { return (encr->encr_ivlength); } size_t cipher_outlength(struct iked_cipher *encr, size_t inlen) { return (roundup(inlen, encr->encr_length)); } struct iked_dsa * dsa_new(uint16_t id, struct iked_hash *prf, int sign) { struct iked_dsa *dsap = NULL, dsa; bzero(&dsa, sizeof(dsa)); switch (id) { case IKEV2_AUTH_SIG: if (sign) dsa.dsa_priv = EVP_sha256(); /* XXX should be passed */ else dsa.dsa_priv = NULL; /* set later by dsa_init() */ break; case IKEV2_AUTH_RSA_SIG: /* RFC5996 says we SHOULD use SHA1 here */ dsa.dsa_priv = EVP_sha1(); break; case IKEV2_AUTH_SHARED_KEY_MIC: if (prf == NULL || prf->hash_priv == NULL) fatalx("dsa_new: invalid PRF"); dsa.dsa_priv = prf->hash_priv; dsa.dsa_hmac = 1; break; case IKEV2_AUTH_DSS_SIG: dsa.dsa_priv = EVP_dss1(); break; case IKEV2_AUTH_ECDSA_256: dsa.dsa_priv = EVP_sha256(); break; case IKEV2_AUTH_ECDSA_384: dsa.dsa_priv = EVP_sha384(); break; case IKEV2_AUTH_ECDSA_521: dsa.dsa_priv = EVP_sha512(); break; default: log_debug("%s: auth method %s not supported", __func__, print_map(id, ikev2_auth_map)); break; } if ((dsap = calloc(1, sizeof(*dsap))) == NULL) { log_debug("%s: alloc dsa ctx", __func__); return (NULL); } memcpy(dsap, &dsa, sizeof(*dsap)); dsap->dsa_method = id; dsap->dsa_sign = sign; if (dsap->dsa_hmac) { if ((dsap->dsa_ctx = calloc(1, sizeof(HMAC_CTX))) == NULL) { log_debug("%s: alloc hash ctx", __func__); dsa_free(dsap); return (NULL); } HMAC_CTX_init((HMAC_CTX *)dsap->dsa_ctx); } else { if ((dsap->dsa_ctx = EVP_MD_CTX_create()) == NULL) { log_debug("%s: alloc digest ctx", __func__); dsa_free(dsap); return (NULL); } } return (dsap); } struct iked_dsa * dsa_sign_new(uint16_t id, struct iked_hash *prf) { return (dsa_new(id, prf, 1)); } struct iked_dsa * dsa_verify_new(uint16_t id, struct iked_hash *prf) { return (dsa_new(id, prf, 0)); } void dsa_free(struct iked_dsa *dsa) { if (dsa == NULL) return; if (dsa->dsa_hmac) { HMAC_CTX_cleanup((HMAC_CTX *)dsa->dsa_ctx); free(dsa->dsa_ctx); } else { EVP_MD_CTX_destroy((EVP_MD_CTX *)dsa->dsa_ctx); if (dsa->dsa_key) EVP_PKEY_free(dsa->dsa_key); if (dsa->dsa_cert) X509_free(dsa->dsa_cert); } ibuf_release(dsa->dsa_keydata); free(dsa); } struct ibuf * dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, uint8_t type) { BIO *rawcert = NULL; X509 *cert = NULL; RSA *rsa = NULL; EVP_PKEY *pkey = NULL; ibuf_release(dsa->dsa_keydata); if ((dsa->dsa_keydata = ibuf_new(key, keylen)) == NULL) { log_debug("%s: alloc signature key", __func__); return (NULL); } if ((rawcert = BIO_new_mem_buf(key, keylen)) == NULL) goto err; switch (type) { case IKEV2_CERT_X509_CERT: if ((cert = d2i_X509_bio(rawcert, NULL)) == NULL) goto sslerr; if ((pkey = X509_get_pubkey(cert)) == NULL) goto sslerr; dsa->dsa_cert = cert; dsa->dsa_key = pkey; break; case IKEV2_CERT_RSA_KEY: if (dsa->dsa_sign) { if ((rsa = d2i_RSAPrivateKey_bio(rawcert, NULL)) == NULL) goto sslerr; } else { if ((rsa = d2i_RSAPublicKey_bio(rawcert, NULL)) == NULL) goto sslerr; } if ((pkey = EVP_PKEY_new()) == NULL) goto sslerr; if (!EVP_PKEY_set1_RSA(pkey, rsa)) goto sslerr; RSA_free(rsa); /* pkey now has the reference */ dsa->dsa_cert = NULL; dsa->dsa_key = pkey; break; default: if (dsa->dsa_hmac) break; log_debug("%s: unsupported key type", __func__); goto err; } return (dsa->dsa_keydata); sslerr: ca_sslerror(__func__); err: log_debug("%s: error", __func__); if (rsa != NULL) RSA_free(rsa); if (pkey != NULL) EVP_PKEY_free(pkey); if (cert != NULL) X509_free(cert); if (rawcert != NULL) BIO_free(rawcert); ibuf_release(dsa->dsa_keydata); return (NULL); } int _dsa_verify_init(struct iked_dsa *dsa, const uint8_t *sig, size_t len) { uint8_t oidlen; size_t i; if (dsa->dsa_priv != NULL) return (0); /* * For IKEV2_AUTH_SIG the oid of the authentication signature * is encoded in the first bytes of the auth message. */ if (dsa->dsa_method != IKEV2_AUTH_SIG) { log_debug("%s: dsa_priv not set for %s", __func__, print_map(dsa->dsa_method, ikev2_auth_map)); return (-1); } if (sig == NULL) { log_debug("%s: signature missing", __func__); return (-1); } if (len < 1) { log_debug("%s: signature (%zu) too small for oid length", __func__, len); return (-1); } memcpy(&oidlen, sig, sizeof(oidlen)); if (len < (size_t)oidlen + 1) { log_debug("%s: signature (%zu) too small for oid (%u)", __func__, len, oidlen); return (-1); } for (i = 0; i < nitems(schemes); i++) { if (oidlen == schemes[i].sc_len && memcmp(sig + 1, schemes[i].sc_oid, schemes[i].sc_len) == 0) { dsa->dsa_priv = (*schemes[i].sc_md)(); log_debug("%s: signature scheme %zd selected", __func__, i); return (0); } } log_debug("%s: unsupported signature (%d)", __func__, oidlen); return (-1); } int dsa_init(struct iked_dsa *dsa, const void *buf, size_t len) { int ret; if (dsa->dsa_hmac) { if (!HMAC_Init_ex(dsa->dsa_ctx, ibuf_data(dsa->dsa_keydata), ibuf_length(dsa->dsa_keydata), dsa->dsa_priv, NULL)) return (-1); return (0); } if (dsa->dsa_sign) ret = EVP_SignInit_ex(dsa->dsa_ctx, dsa->dsa_priv, NULL); else { if ((ret = _dsa_verify_init(dsa, buf, len)) != 0) return (ret); ret = EVP_VerifyInit_ex(dsa->dsa_ctx, dsa->dsa_priv, NULL); } return (ret ? 0 : -1); } int dsa_update(struct iked_dsa *dsa, const void *buf, size_t len) { int ret = 1; if (dsa->dsa_hmac) ret = HMAC_Update(dsa->dsa_ctx, buf, len); else if (dsa->dsa_sign) ret = EVP_SignUpdate(dsa->dsa_ctx, buf, len); else ret = EVP_VerifyUpdate(dsa->dsa_ctx, buf, len); return (ret ? 0 : -1); } /* Prefix signature hash with encoded type */ int _dsa_sign_encode(struct iked_dsa *dsa, uint8_t *ptr, size_t *offp) { if (offp) *offp = 0; if (dsa->dsa_method != IKEV2_AUTH_SIG) return (0); if (dsa->dsa_priv != EVP_sha256()) return (-1); if (ptr) { ptr[0] = sizeof(sha256WithRSAEncryption); memcpy(ptr + 1, sha256WithRSAEncryption, sizeof(sha256WithRSAEncryption)); } if (offp) *offp = 1 + sizeof(sha256WithRSAEncryption); return (0); } size_t dsa_length(struct iked_dsa *dsa) { size_t off = 0; if (dsa->dsa_hmac) return (EVP_MD_size(dsa->dsa_priv)); if (_dsa_sign_encode(dsa, NULL, &off) < 0) fatal("dsa_length: internal error"); return (EVP_PKEY_size(dsa->dsa_key) + off); } ssize_t dsa_sign_final(struct iked_dsa *dsa, void *buf, size_t len) { unsigned int siglen; size_t off = 0; uint8_t *ptr = buf; if (len < dsa_length(dsa)) return (-1); if (dsa->dsa_hmac) { if (!HMAC_Final(dsa->dsa_ctx, buf, &siglen)) return (-1); } else { if (_dsa_sign_encode(dsa, ptr, &off) < 0) return (-1); if (!EVP_SignFinal(dsa->dsa_ctx, ptr + off, &siglen, dsa->dsa_key)) return (-1); siglen += off; } return (siglen); } size_t _dsa_verify_offset(struct iked_dsa *dsa, uint8_t *ptr) { /* * XXX assumes that _dsa_verify_init() has already checked * the encoded method. */ if (dsa->dsa_method == IKEV2_AUTH_SIG) return (ptr[0] + 1); return (0); } ssize_t dsa_verify_final(struct iked_dsa *dsa, void *buf, size_t len) { uint8_t sig[EVP_MAX_MD_SIZE]; unsigned int siglen = sizeof(sig); uint8_t *ptr = buf; size_t off = 0; if (dsa->dsa_hmac) { if (!HMAC_Final(dsa->dsa_ctx, sig, &siglen)) return (-1); if (siglen != len || memcmp(buf, sig, siglen) != 0) return (-1); } else { if ((off = _dsa_verify_offset(dsa, ptr)) >= len) return (-1); if (EVP_VerifyFinal(dsa->dsa_ctx, ptr + off, len - off, dsa->dsa_key) != 1) { ca_sslerror(__func__); return (-1); } } return (0); }