summaryrefslogtreecommitdiffstats
path: root/ipsec-tools/src/racoon/algorithm.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipsec-tools/src/racoon/algorithm.c')
-rw-r--r--ipsec-tools/src/racoon/algorithm.c957
1 files changed, 957 insertions, 0 deletions
diff --git a/ipsec-tools/src/racoon/algorithm.c b/ipsec-tools/src/racoon/algorithm.c
new file mode 100644
index 00000000..3fd50f6e
--- /dev/null
+++ b/ipsec-tools/src/racoon/algorithm.c
@@ -0,0 +1,957 @@
+/* $NetBSD: algorithm.c,v 1.8 2006/10/06 12:02:27 manu Exp $ */
+
+/* Id: algorithm.c,v 1.15 2006/05/23 20:23:09 manubsd Exp */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+#include "var.h"
+#include "misc.h"
+#include "vmbuf.h"
+#include "plog.h"
+#include "debug.h"
+
+#include "crypto_openssl.h"
+#include "dhgroup.h"
+#include "algorithm.h"
+#include "oakley.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "ipsec_doi.h"
+#include "gcmalloc.h"
+
+static struct hash_algorithm oakley_hashdef[] = {
+{ "md5", algtype_md5, OAKLEY_ATTR_HASH_ALG_MD5,
+ eay_md5_init, eay_md5_update,
+ eay_md5_final, eay_md5_hashlen,
+ eay_md5_one, },
+{ "sha1", algtype_sha1, OAKLEY_ATTR_HASH_ALG_SHA,
+ eay_sha1_init, eay_sha1_update,
+ eay_sha1_final, eay_sha1_hashlen,
+ eay_sha1_one, },
+#ifdef WITH_SHA2
+{ "sha2_256", algtype_sha2_256, OAKLEY_ATTR_HASH_ALG_SHA2_256,
+ eay_sha2_256_init, eay_sha2_256_update,
+ eay_sha2_256_final, eay_sha2_256_hashlen,
+ eay_sha2_256_one, },
+{ "sha2_384", algtype_sha2_384, OAKLEY_ATTR_HASH_ALG_SHA2_384,
+ eay_sha2_384_init, eay_sha2_384_update,
+ eay_sha2_384_final, eay_sha2_384_hashlen,
+ eay_sha2_384_one, },
+{ "sha2_512", algtype_sha2_512, OAKLEY_ATTR_HASH_ALG_SHA2_512,
+ eay_sha2_512_init, eay_sha2_512_update,
+ eay_sha2_512_final, eay_sha2_512_hashlen,
+ eay_sha2_512_one, },
+#endif
+};
+
+static struct hmac_algorithm oakley_hmacdef[] = {
+{ "hmac_md5", algtype_md5, OAKLEY_ATTR_HASH_ALG_MD5,
+ eay_hmacmd5_init, eay_hmacmd5_update,
+ eay_hmacmd5_final, NULL,
+ eay_hmacmd5_one, },
+{ "hmac_sha1", algtype_sha1, OAKLEY_ATTR_HASH_ALG_SHA,
+ eay_hmacsha1_init, eay_hmacsha1_update,
+ eay_hmacsha1_final, NULL,
+ eay_hmacsha1_one, },
+#ifdef WITH_SHA2
+{ "hmac_sha2_256", algtype_sha2_256, OAKLEY_ATTR_HASH_ALG_SHA2_256,
+ eay_hmacsha2_256_init, eay_hmacsha2_256_update,
+ eay_hmacsha2_256_final, NULL,
+ eay_hmacsha2_256_one, },
+{ "hmac_sha2_384", algtype_sha2_384, OAKLEY_ATTR_HASH_ALG_SHA2_384,
+ eay_hmacsha2_384_init, eay_hmacsha2_384_update,
+ eay_hmacsha2_384_final, NULL,
+ eay_hmacsha2_384_one, },
+{ "hmac_sha2_512", algtype_sha2_512, OAKLEY_ATTR_HASH_ALG_SHA2_512,
+ eay_hmacsha2_512_init, eay_hmacsha2_512_update,
+ eay_hmacsha2_512_final, NULL,
+ eay_hmacsha2_512_one, },
+#endif
+};
+
+static struct enc_algorithm oakley_encdef[] = {
+{ "des", algtype_des, OAKLEY_ATTR_ENC_ALG_DES, 8,
+ eay_des_encrypt, eay_des_decrypt,
+ eay_des_weakkey, eay_des_keylen, },
+#ifdef HAVE_OPENSSL_IDEA_H
+{ "idea", algtype_idea, OAKLEY_ATTR_ENC_ALG_IDEA, 8,
+ eay_idea_encrypt, eay_idea_decrypt,
+ eay_idea_weakkey, eay_idea_keylen, },
+#endif
+{ "blowfish", algtype_blowfish, OAKLEY_ATTR_ENC_ALG_BLOWFISH, 8,
+ eay_bf_encrypt, eay_bf_decrypt,
+ eay_bf_weakkey, eay_bf_keylen, },
+#ifdef HAVE_OPENSSL_RC5_H
+{ "rc5", algtype_rc5, OAKLEY_ATTR_ENC_ALG_RC5, 8,
+ eay_rc5_encrypt, eay_rc5_decrypt,
+ eay_rc5_weakkey, eay_rc5_keylen, },
+#endif
+{ "3des", algtype_3des, OAKLEY_ATTR_ENC_ALG_3DES, 8,
+ eay_3des_encrypt, eay_3des_decrypt,
+ eay_3des_weakkey, eay_3des_keylen, },
+{ "cast", algtype_cast128, OAKLEY_ATTR_ENC_ALG_CAST, 8,
+ eay_cast_encrypt, eay_cast_decrypt,
+ eay_cast_weakkey, eay_cast_keylen, },
+{ "aes", algtype_aes, OAKLEY_ATTR_ENC_ALG_AES, 16,
+ eay_aes_encrypt, eay_aes_decrypt,
+ eay_aes_weakkey, eay_aes_keylen, },
+#ifdef HAVE_OPENSSL_CAMELLIA_H
+{ "camellia", algtype_camellia, OAKLEY_ATTR_ENC_ALG_CAMELLIA, 16,
+ eay_camellia_encrypt, eay_camellia_decrypt,
+ eay_camellia_weakkey, eay_camellia_keylen, },
+#endif
+};
+
+static struct enc_algorithm ipsec_encdef[] = {
+{ "des-iv64", algtype_des_iv64, IPSECDOI_ESP_DES_IV64, 8,
+ NULL, NULL,
+ NULL, eay_des_keylen, },
+{ "des", algtype_des, IPSECDOI_ESP_DES, 8,
+ NULL, NULL,
+ NULL, eay_des_keylen, },
+{ "3des", algtype_3des, IPSECDOI_ESP_3DES, 8,
+ NULL, NULL,
+ NULL, eay_3des_keylen, },
+#ifdef HAVE_OPENSSL_RC5_H
+{ "rc5", algtype_rc5, IPSECDOI_ESP_RC5, 8,
+ NULL, NULL,
+ NULL, eay_rc5_keylen, },
+#endif
+{ "cast", algtype_cast128, IPSECDOI_ESP_CAST, 8,
+ NULL, NULL,
+ NULL, eay_cast_keylen, },
+{ "blowfish", algtype_blowfish, IPSECDOI_ESP_BLOWFISH, 8,
+ NULL, NULL,
+ NULL, eay_bf_keylen, },
+{ "des-iv32", algtype_des_iv32, IPSECDOI_ESP_DES_IV32, 8,
+ NULL, NULL,
+ NULL, eay_des_keylen, },
+{ "null", algtype_null_enc, IPSECDOI_ESP_NULL, 8,
+ NULL, NULL,
+ NULL, eay_null_keylen, },
+{ "aes", algtype_aes, IPSECDOI_ESP_AES, 16,
+ NULL, NULL,
+ NULL, eay_aes_keylen, },
+{ "twofish", algtype_twofish, IPSECDOI_ESP_TWOFISH, 16,
+ NULL, NULL,
+ NULL, eay_twofish_keylen, },
+#ifdef HAVE_OPENSSL_IDEA_H
+{ "3idea", algtype_3idea, IPSECDOI_ESP_3IDEA, 8,
+ NULL, NULL,
+ NULL, NULL, },
+{ "idea", algtype_idea, IPSECDOI_ESP_IDEA, 8,
+ NULL, NULL,
+ NULL, NULL, },
+#endif
+{ "rc4", algtype_rc4, IPSECDOI_ESP_RC4, 8,
+ NULL, NULL,
+ NULL, NULL, },
+#ifdef HAVE_OPENSSL_CAMELLIA_H
+{ "camellia", algtype_camellia, IPSECDOI_ESP_CAMELLIA, 16,
+ NULL, NULL,
+ NULL, eay_camellia_keylen, },
+#endif
+};
+
+static struct hmac_algorithm ipsec_hmacdef[] = {
+{ "md5", algtype_hmac_md5, IPSECDOI_ATTR_AUTH_HMAC_MD5,
+ NULL, NULL,
+ NULL, eay_md5_hashlen,
+ NULL, },
+{ "sha1", algtype_hmac_sha1, IPSECDOI_ATTR_AUTH_HMAC_SHA1,
+ NULL, NULL,
+ NULL, eay_sha1_hashlen,
+ NULL, },
+{ "kpdk", algtype_kpdk, IPSECDOI_ATTR_AUTH_KPDK,
+ NULL, NULL,
+ NULL, eay_kpdk_hashlen,
+ NULL, },
+{ "null", algtype_non_auth, IPSECDOI_ATTR_AUTH_NONE,
+ NULL, NULL,
+ NULL, eay_null_hashlen,
+ NULL, },
+#ifdef WITH_SHA2
+{ "hmac_sha2_256", algtype_hmac_sha2_256,IPSECDOI_ATTR_AUTH_HMAC_SHA2_256,
+ NULL, NULL,
+ NULL, eay_sha2_256_hashlen,
+ NULL, },
+{ "hmac_sha2_384", algtype_hmac_sha2_384,IPSECDOI_ATTR_AUTH_HMAC_SHA2_384,
+ NULL, NULL,
+ NULL, eay_sha2_384_hashlen,
+ NULL, },
+{ "hmac_sha2_512", algtype_hmac_sha2_512,IPSECDOI_ATTR_AUTH_HMAC_SHA2_512,
+ NULL, NULL,
+ NULL, eay_sha2_512_hashlen,
+ NULL, },
+#endif
+};
+
+static struct misc_algorithm ipsec_compdef[] = {
+{ "oui", algtype_oui, IPSECDOI_IPCOMP_OUI, },
+{ "deflate", algtype_deflate, IPSECDOI_IPCOMP_DEFLATE, },
+{ "lzs", algtype_lzs, IPSECDOI_IPCOMP_LZS, },
+};
+
+/*
+ * In case of asymetric modes (hybrid xauth), what's racoon mode of
+ * operations ; it seems that the proposal should always use the
+ * initiator half (unless a server initiates a connection, which is
+ * not handled, and probably not useful).
+ */
+static struct misc_algorithm oakley_authdef[] = {
+{ "pre_shared_key", algtype_psk, OAKLEY_ATTR_AUTH_METHOD_PSKEY, },
+{ "dsssig", algtype_dsssig, OAKLEY_ATTR_AUTH_METHOD_DSSSIG, },
+{ "rsasig", algtype_rsasig, OAKLEY_ATTR_AUTH_METHOD_RSASIG, },
+{ "rsaenc", algtype_rsaenc, OAKLEY_ATTR_AUTH_METHOD_RSAENC, },
+{ "rsarev", algtype_rsarev, OAKLEY_ATTR_AUTH_METHOD_RSAREV, },
+
+{ "gssapi_krb", algtype_gssapikrb,
+ OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB, },
+
+#ifdef ENABLE_HYBRID
+{ "hybrid_rsa_server", algtype_hybrid_rsa_s,
+ OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R, },
+
+{ "hybrid_dss_server", algtype_hybrid_dss_s,
+ OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R, },
+
+{ "xauth_psk_server", algtype_xauth_psk_s,
+ OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R, },
+
+{ "xauth_rsa_server", algtype_xauth_rsa_s,
+ OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R, },
+
+{ "hybrid_rsa_client", algtype_hybrid_rsa_c,
+ OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I, },
+
+{ "hybrid_dss_client", algtype_hybrid_dss_c,
+ OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I, },
+
+{ "xauth_psk_client", algtype_xauth_psk_c,
+ OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I, },
+
+{ "xauth_rsa_client", algtype_xauth_rsa_c,
+ OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I, },
+#endif
+};
+
+static struct dh_algorithm oakley_dhdef[] = {
+{ "modp768", algtype_modp768, OAKLEY_ATTR_GRP_DESC_MODP768,
+ &dh_modp768, },
+{ "modp1024", algtype_modp1024, OAKLEY_ATTR_GRP_DESC_MODP1024,
+ &dh_modp1024, },
+{ "modp1536", algtype_modp1536, OAKLEY_ATTR_GRP_DESC_MODP1536,
+ &dh_modp1536, },
+{ "modp2048", algtype_modp2048, OAKLEY_ATTR_GRP_DESC_MODP2048,
+ &dh_modp2048, },
+{ "modp3072", algtype_modp3072, OAKLEY_ATTR_GRP_DESC_MODP3072,
+ &dh_modp3072, },
+{ "modp4096", algtype_modp4096, OAKLEY_ATTR_GRP_DESC_MODP4096,
+ &dh_modp4096, },
+{ "modp6144", algtype_modp6144, OAKLEY_ATTR_GRP_DESC_MODP6144,
+ &dh_modp6144, },
+{ "modp8192", algtype_modp8192, OAKLEY_ATTR_GRP_DESC_MODP8192,
+ &dh_modp8192, },
+};
+
+static struct hash_algorithm *alg_oakley_hashdef __P((int));
+static struct hmac_algorithm *alg_oakley_hmacdef __P((int));
+static struct enc_algorithm *alg_oakley_encdef __P((int));
+static struct enc_algorithm *alg_ipsec_encdef __P((int));
+static struct hmac_algorithm *alg_ipsec_hmacdef __P((int));
+static struct dh_algorithm *alg_oakley_dhdef __P((int));
+
+/* oakley hash algorithm */
+static struct hash_algorithm *
+alg_oakley_hashdef(doi)
+ int doi;
+{
+ int i;
+
+ for (i = 0; i < ARRAYLEN(oakley_hashdef); i++)
+ if (doi == oakley_hashdef[i].doi) {
+ plog(LLV_DEBUG, LOCATION, NULL, "hash(%s)\n",
+ oakley_hashdef[i].name);
+ return &oakley_hashdef[i];
+ }
+ return NULL;
+}
+
+int
+alg_oakley_hashdef_ok(doi)
+ int doi;
+{
+ struct hash_algorithm *f;
+
+ f = alg_oakley_hashdef(doi);
+ if (f == NULL)
+ return 0;
+
+ return 1;
+}
+
+int
+alg_oakley_hashdef_doi(type)
+ int type;
+{
+ int i, res = -1;
+
+ for (i = 0; i < ARRAYLEN(oakley_hashdef); i++)
+ if (type == oakley_hashdef[i].type) {
+ res = oakley_hashdef[i].doi;
+ break;
+ }
+ return res;
+}
+
+int
+alg_oakley_hashdef_hashlen(doi)
+ int doi;
+{
+ struct hash_algorithm *f;
+
+ f = alg_oakley_hashdef(doi);
+ if (f == NULL || f->hashlen == NULL)
+ return 0;
+
+ return (f->hashlen)();
+}
+
+const char *
+alg_oakley_hashdef_name (doi)
+ int doi;
+{
+ struct hash_algorithm *f;
+
+ f = alg_oakley_hashdef(doi);
+ if (f == NULL)
+ return "*UNKNOWN*";
+
+ return f->name;
+}
+
+vchar_t *
+alg_oakley_hashdef_one(doi, buf)
+ int doi;
+ vchar_t *buf;
+{
+ struct hash_algorithm *f;
+
+ f = alg_oakley_hashdef(doi);
+ if (f == NULL || f->hashlen == NULL)
+ return NULL;
+
+ return (f->one)(buf);
+}
+
+/* oakley hmac algorithm */
+static struct hmac_algorithm *
+alg_oakley_hmacdef(doi)
+ int doi;
+{
+ int i;
+
+ for (i = 0; i < ARRAYLEN(oakley_hmacdef); i++)
+ if (doi == oakley_hmacdef[i].doi) {
+ plog(LLV_DEBUG, LOCATION, NULL, "hmac(%s)\n",
+ oakley_hmacdef[i].name);
+ return &oakley_hmacdef[i];
+ }
+ return NULL;
+}
+
+int
+alg_oakley_hmacdef_doi(type)
+ int type;
+{
+ int i, res = -1;
+
+ for (i = 0; i < ARRAYLEN(oakley_hmacdef); i++)
+ if (type == oakley_hmacdef[i].type) {
+ res = oakley_hmacdef[i].doi;
+ break;
+ }
+ return res;
+}
+
+vchar_t *
+alg_oakley_hmacdef_one(doi, key, buf)
+ int doi;
+ vchar_t *key, *buf;
+{
+ struct hmac_algorithm *f;
+ vchar_t *res;
+#ifdef ENABLE_STATS
+ struct timeval start, end;
+#endif
+
+ f = alg_oakley_hmacdef(doi);
+ if (f == NULL || f->one == NULL)
+ return NULL;
+
+#ifdef ENABLE_STATS
+ gettimeofday(&start, NULL);
+#endif
+
+ res = (f->one)(key, buf);
+
+#ifdef ENABLE_STATS
+ gettimeofday(&end, NULL);
+ syslog(LOG_NOTICE, "%s(%s size=%zu): %8.6f", __func__,
+ f->name, buf->l, timedelta(&start, &end));
+#endif
+
+ return res;
+}
+
+/* oakley encryption algorithm */
+static struct enc_algorithm *
+alg_oakley_encdef(doi)
+ int doi;
+{
+ int i;
+
+ for (i = 0; i < ARRAYLEN(oakley_encdef); i++)
+ if (doi == oakley_encdef[i].doi) {
+ plog(LLV_DEBUG, LOCATION, NULL, "encryption(%s)\n",
+ oakley_encdef[i].name);
+ return &oakley_encdef[i];
+ }
+ return NULL;
+}
+
+int
+alg_oakley_encdef_ok(doi)
+ int doi;
+{
+ struct enc_algorithm *f;
+
+ f = alg_oakley_encdef(doi);
+ if (f == NULL)
+ return 0;
+
+ return 1;
+}
+
+int
+alg_oakley_encdef_doi(type)
+ int type;
+{
+ int i, res = -1;
+
+ for (i = 0; i < ARRAYLEN(oakley_encdef); i++)
+ if (type == oakley_encdef[i].type) {
+ res = oakley_encdef[i].doi;
+ break;
+ }
+ return res;
+}
+
+int
+alg_oakley_encdef_keylen(doi, len)
+ int doi, len;
+{
+ struct enc_algorithm *f;
+
+ f = alg_oakley_encdef(doi);
+ if (f == NULL || f->keylen == NULL)
+ return -1;
+
+ return (f->keylen)(len);
+}
+
+int
+alg_oakley_encdef_blocklen(doi)
+ int doi;
+{
+ struct enc_algorithm *f;
+
+ f = alg_oakley_encdef(doi);
+ if (f == NULL)
+ return -1;
+
+ return f->blocklen;
+}
+
+const char *
+alg_oakley_encdef_name (doi)
+ int doi;
+{
+ struct enc_algorithm *f;
+
+ f = alg_oakley_encdef(doi);
+ if (f == NULL)
+ return "*UNKNOWN*";
+
+ return f->name;
+}
+
+vchar_t *
+alg_oakley_encdef_decrypt(doi, buf, key, iv)
+ int doi;
+ vchar_t *buf, *key, *iv;
+{
+ vchar_t *res;
+ struct enc_algorithm *f;
+#ifdef ENABLE_STATS
+ struct timeval start, end;
+#endif
+
+ f = alg_oakley_encdef(doi);
+ if (f == NULL || f->decrypt == NULL)
+ return NULL;
+
+#ifdef ENABLE_STATS
+ gettimeofday(&start, NULL);
+#endif
+
+ res = (f->decrypt)(buf, key, iv);
+
+#ifdef ENABLE_STATS
+ gettimeofday(&end, NULL);
+ syslog(LOG_NOTICE, "%s(%s klen=%zu size=%zu): %8.6f", __func__,
+ f->name, key->l << 3, buf->l, timedelta(&start, &end));
+#endif
+ return res;
+}
+
+vchar_t *
+alg_oakley_encdef_encrypt(doi, buf, key, iv)
+ int doi;
+ vchar_t *buf, *key, *iv;
+{
+ vchar_t *res;
+ struct enc_algorithm *f;
+#ifdef ENABLE_STATS
+ struct timeval start, end;
+#endif
+
+ f = alg_oakley_encdef(doi);
+ if (f == NULL || f->encrypt == NULL)
+ return NULL;
+
+#ifdef ENABLE_STATS
+ gettimeofday(&start, NULL);
+#endif
+
+ res = (f->encrypt)(buf, key, iv);
+
+#ifdef ENABLE_STATS
+ gettimeofday(&end, NULL);
+ syslog(LOG_NOTICE, "%s(%s klen=%zu size=%zu): %8.6f", __func__,
+ f->name, key->l << 3, buf->l, timedelta(&start, &end));
+#endif
+ return res;
+}
+
+/* ipsec encryption algorithm */
+static struct enc_algorithm *
+alg_ipsec_encdef(doi)
+ int doi;
+{
+ int i;
+
+ for (i = 0; i < ARRAYLEN(ipsec_encdef); i++)
+ if (doi == ipsec_encdef[i].doi) {
+ plog(LLV_DEBUG, LOCATION, NULL, "encryption(%s)\n",
+ ipsec_encdef[i].name);
+ return &ipsec_encdef[i];
+ }
+ return NULL;
+}
+
+int
+alg_ipsec_encdef_doi(type)
+ int type;
+{
+ int i, res = -1;
+
+ for (i = 0; i < ARRAYLEN(ipsec_encdef); i++)
+ if (type == ipsec_encdef[i].type) {
+ res = ipsec_encdef[i].doi;
+ break;
+ }
+ return res;
+}
+
+int
+alg_ipsec_encdef_keylen(doi, len)
+ int doi, len;
+{
+ struct enc_algorithm *f;
+
+ f = alg_ipsec_encdef(doi);
+ if (f == NULL || f->keylen == NULL)
+ return -1;
+
+ return (f->keylen)(len);
+}
+
+/* ipsec hmac algorithm */
+static struct hmac_algorithm *
+alg_ipsec_hmacdef(doi)
+ int doi;
+{
+ int i;
+
+ for (i = 0; i < ARRAYLEN(ipsec_hmacdef); i++)
+ if (doi == ipsec_hmacdef[i].doi) {
+ plog(LLV_DEBUG, LOCATION, NULL, "hmac(%s)\n",
+ ipsec_hmacdef[i].name);
+ return &ipsec_hmacdef[i];
+ }
+ return NULL;
+}
+
+int
+alg_ipsec_hmacdef_doi(type)
+ int type;
+{
+ int i, res = -1;
+
+ for (i = 0; i < ARRAYLEN(ipsec_hmacdef); i++)
+ if (type == ipsec_hmacdef[i].type) {
+ res = ipsec_hmacdef[i].doi;
+ break;
+ }
+ return res;
+}
+
+int
+alg_ipsec_hmacdef_hashlen(doi)
+ int doi;
+{
+ struct hmac_algorithm *f;
+
+ f = alg_ipsec_hmacdef(doi);
+ if (f == NULL || f->hashlen == NULL)
+ return -1;
+
+ return (f->hashlen)();
+}
+
+/* ip compression */
+int
+alg_ipsec_compdef_doi(type)
+ int type;
+{
+ int i, res = -1;
+
+ for (i = 0; i < ARRAYLEN(ipsec_compdef); i++)
+ if (type == ipsec_compdef[i].type) {
+ res = ipsec_compdef[i].doi;
+ break;
+ }
+ return res;
+}
+
+/* dh algorithm */
+static struct dh_algorithm *
+alg_oakley_dhdef(doi)
+ int doi;
+{
+ int i;
+
+ for (i = 0; i < ARRAYLEN(oakley_dhdef); i++)
+ if (doi == oakley_dhdef[i].doi) {
+ plog(LLV_DEBUG, LOCATION, NULL, "hmac(%s)\n",
+ oakley_dhdef[i].name);
+ return &oakley_dhdef[i];
+ }
+ return NULL;
+}
+
+int
+alg_oakley_dhdef_ok(doi)
+ int doi;
+{
+ struct dh_algorithm *f;
+
+ f = alg_oakley_dhdef(doi);
+ if (f == NULL)
+ return 0;
+
+ return 1;
+}
+
+int
+alg_oakley_dhdef_doi(type)
+ int type;
+{
+ int i, res = -1;
+
+ for (i = 0; i < ARRAYLEN(oakley_dhdef); i++)
+ if (type == oakley_dhdef[i].type) {
+ res = oakley_dhdef[i].doi;
+ break;
+ }
+ return res;
+}
+
+struct dhgroup *
+alg_oakley_dhdef_group(doi)
+ int doi;
+{
+ struct dh_algorithm *f;
+
+ f = alg_oakley_dhdef(doi);
+ if (f == NULL || f->dhgroup == NULL)
+ return NULL;
+
+ return f->dhgroup;
+}
+
+const char *
+alg_oakley_dhdef_name (doi)
+ int doi;
+{
+ struct dh_algorithm *f;
+
+ f = alg_oakley_dhdef(doi);
+ if (f == NULL)
+ return "*UNKNOWN*";
+ return f->name;
+}
+
+/* authentication method */
+int
+alg_oakley_authdef_doi(type)
+ int type;
+{
+ int i, res = -1;
+
+ for (i = 0; i < ARRAYLEN(oakley_authdef); i++)
+ if (type == oakley_authdef[i].type) {
+ res = oakley_authdef[i].doi;
+ break;
+ }
+ return res;
+}
+
+const char *
+alg_oakley_authdef_name (doi)
+ int doi;
+{
+ int i;
+
+ for (i = 0; i < ARRAYLEN(oakley_authdef); i++)
+ if (doi == oakley_authdef[i].doi) {
+ return oakley_authdef[i].name;
+ }
+ return "*UNKNOWN*";
+}
+
+/*
+ * give the default key length
+ * OUT: -1: NG
+ * 0: fixed key cipher, key length not allowed
+ * positive: default key length
+ */
+int
+default_keylen(class, type)
+ int class, type;
+{
+
+ switch (class) {
+ case algclass_isakmp_enc:
+ case algclass_ipsec_enc:
+ break;
+ default:
+ return 0;
+ }
+
+ switch (type) {
+ case algtype_blowfish:
+ case algtype_rc5:
+ case algtype_cast128:
+ case algtype_aes:
+ case algtype_twofish:
+ case algtype_camellia:
+ return 128;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * check key length
+ * OUT: -1: NG
+ * 0: OK
+ */
+int
+check_keylen(class, type, len)
+ int class, type, len;
+{
+ int badrange;
+
+ switch (class) {
+ case algclass_isakmp_enc:
+ case algclass_ipsec_enc:
+ break;
+ default:
+ /* unknown class, punt */
+ plog(LLV_ERROR, LOCATION, NULL,
+ "unknown algclass %d\n", class);
+ return -1;
+ }
+
+ /* key length must be multiple of 8 bytes - RFC2451 2.2 */
+ switch (type) {
+ case algtype_blowfish:
+ case algtype_rc5:
+ case algtype_cast128:
+ case algtype_aes:
+ case algtype_twofish:
+ case algtype_camellia:
+ if (len % 8 != 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "key length %d is not multiple of 8\n", len);
+ return -1;
+ }
+ break;
+ }
+
+ /* key length range */
+ badrange = 0;
+ switch (type) {
+ case algtype_blowfish:
+ if (len < 40 || 448 < len)
+ badrange++;
+ break;
+ case algtype_rc5:
+ if (len < 40 || 2040 < len)
+ badrange++;
+ break;
+ case algtype_cast128:
+ if (len < 40 || 128 < len)
+ badrange++;
+ break;
+ case algtype_aes:
+ if (!(len == 128 || len == 192 || len == 256))
+ badrange++;
+ break;
+ case algtype_twofish:
+ if (len < 40 || 256 < len)
+ badrange++;
+ break;
+ case algtype_camellia:
+ if (!(len == 128 || len == 192 || len == 256))
+ badrange++;
+ break;
+ default:
+ if (len) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "key length is not allowed");
+ return -1;
+ }
+ break;
+ }
+ if (badrange) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "key length out of range\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * convert algorithm type to DOI value.
+ * OUT -1 : NG
+ * other: converted.
+ */
+int
+algtype2doi(class, type)
+ int class, type;
+{
+ int res = -1;
+
+ switch (class) {
+ case algclass_ipsec_enc:
+ res = alg_ipsec_encdef_doi(type);
+ break;
+ case algclass_ipsec_auth:
+ res = alg_ipsec_hmacdef_doi(type);
+ break;
+ case algclass_ipsec_comp:
+ res = alg_ipsec_compdef_doi(type);
+ break;
+ case algclass_isakmp_enc:
+ res = alg_oakley_encdef_doi(type);
+ break;
+ case algclass_isakmp_hash:
+ res = alg_oakley_hashdef_doi(type);
+ break;
+ case algclass_isakmp_dh:
+ res = alg_oakley_dhdef_doi(type);
+ break;
+ case algclass_isakmp_ameth:
+ res = alg_oakley_authdef_doi(type);
+ break;
+ }
+ return res;
+}
+
+/*
+ * convert algorithm class to DOI value.
+ * OUT -1 : NG
+ * other: converted.
+ */
+int
+algclass2doi(class)
+ int class;
+{
+ switch (class) {
+ case algclass_ipsec_enc:
+ return IPSECDOI_PROTO_IPSEC_ESP;
+ case algclass_ipsec_auth:
+ return IPSECDOI_ATTR_AUTH;
+ case algclass_ipsec_comp:
+ return IPSECDOI_PROTO_IPCOMP;
+ case algclass_isakmp_enc:
+ return OAKLEY_ATTR_ENC_ALG;
+ case algclass_isakmp_hash:
+ return OAKLEY_ATTR_HASH_ALG;
+ case algclass_isakmp_dh:
+ return OAKLEY_ATTR_GRP_DESC;
+ case algclass_isakmp_ameth:
+ return OAKLEY_ATTR_AUTH_METHOD;
+ default:
+ return -1;
+ }
+ /*NOTREACHED*/
+ return -1;
+}