summaryrefslogtreecommitdiff
path: root/src/openvpn/httpdigest.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvpn/httpdigest.c')
-rw-r--r--src/openvpn/httpdigest.c154
1 files changed, 154 insertions, 0 deletions
diff --git a/src/openvpn/httpdigest.c b/src/openvpn/httpdigest.c
new file mode 100644
index 0000000..78b8344
--- /dev/null
+++ b/src/openvpn/httpdigest.c
@@ -0,0 +1,154 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single TCP/UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+#if PROXY_DIGEST_AUTH
+
+#include "crypto.h"
+#include "httpdigest.h"
+
+static void
+CvtHex(
+ IN HASH Bin,
+ OUT HASHHEX Hex
+ )
+{
+ unsigned short i;
+ unsigned char j;
+
+ for (i = 0; i < HASHLEN; i++) {
+ j = (Bin[i] >> 4) & 0xf;
+ if (j <= 9)
+ Hex[i*2] = (j + '0');
+ else
+ Hex[i*2] = (j + 'a' - 10);
+ j = Bin[i] & 0xf;
+ if (j <= 9)
+ Hex[i*2+1] = (j + '0');
+ else
+ Hex[i*2+1] = (j + 'a' - 10);
+ };
+ Hex[HASHHEXLEN] = '\0';
+};
+
+/* calculate H(A1) as per spec */
+void
+DigestCalcHA1(
+ IN char * pszAlg,
+ IN char * pszUserName,
+ IN char * pszRealm,
+ IN char * pszPassword,
+ IN char * pszNonce,
+ IN char * pszCNonce,
+ OUT HASHHEX SessionKey
+ )
+{
+ HASH HA1;
+ md_ctx_t md5_ctx;
+ const md_kt_t *md5_kt = md_kt_get("MD5");
+
+ md_ctx_init(&md5_ctx, md5_kt);
+ md_ctx_update(&md5_ctx, pszUserName, strlen(pszUserName));
+ md_ctx_update(&md5_ctx, ":", 1);
+ md_ctx_update(&md5_ctx, pszRealm, strlen(pszRealm));
+ md_ctx_update(&md5_ctx, ":", 1);
+ md_ctx_update(&md5_ctx, pszPassword, strlen(pszPassword));
+ md_ctx_final(&md5_ctx, HA1);
+ if (pszAlg && strcasecmp(pszAlg, "md5-sess") == 0)
+ {
+ md_ctx_init(&md5_ctx, md5_kt);
+ md_ctx_update(&md5_ctx, HA1, HASHLEN);
+ md_ctx_update(&md5_ctx, ":", 1);
+ md_ctx_update(&md5_ctx, pszNonce, strlen(pszNonce));
+ md_ctx_update(&md5_ctx, ":", 1);
+ md_ctx_update(&md5_ctx, pszCNonce, strlen(pszCNonce));
+ md_ctx_final(&md5_ctx, HA1);
+ };
+ md_ctx_cleanup(&md5_ctx);
+ CvtHex(HA1, SessionKey);
+}
+
+/* calculate request-digest/response-digest as per HTTP Digest spec */
+void
+DigestCalcResponse(
+ IN HASHHEX HA1, /* H(A1) */
+ IN char * pszNonce, /* nonce from server */
+ IN char * pszNonceCount, /* 8 hex digits */
+ IN char * pszCNonce, /* client nonce */
+ IN char * pszQop, /* qop-value: "", "auth", "auth-int" */
+ IN char * pszMethod, /* method from the request */
+ IN char * pszDigestUri, /* requested URL */
+ IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
+ OUT HASHHEX Response /* request-digest or response-digest */
+ )
+{
+ HASH HA2;
+ HASH RespHash;
+ HASHHEX HA2Hex;
+
+ md_ctx_t md5_ctx;
+ const md_kt_t *md5_kt = md_kt_get("MD5");
+
+ /* calculate H(A2) */
+ md_ctx_init(&md5_ctx, md5_kt);
+ md_ctx_update(&md5_ctx, pszMethod, strlen(pszMethod));
+ md_ctx_update(&md5_ctx, ":", 1);
+ md_ctx_update(&md5_ctx, pszDigestUri, strlen(pszDigestUri));
+ if (strcasecmp(pszQop, "auth-int") == 0)
+ {
+ md_ctx_update(&md5_ctx, ":", 1);
+ md_ctx_update(&md5_ctx, HEntity, HASHHEXLEN);
+ };
+ md_ctx_final(&md5_ctx, HA2);
+ CvtHex(HA2, HA2Hex);
+
+ /* calculate response */
+ md_ctx_init(&md5_ctx, md5_kt);
+ md_ctx_update(&md5_ctx, HA1, HASHHEXLEN);
+ md_ctx_update(&md5_ctx, ":", 1);
+ md_ctx_update(&md5_ctx, pszNonce, strlen(pszNonce));
+ md_ctx_update(&md5_ctx, ":", 1);
+ if (*pszQop)
+ {
+ md_ctx_update(&md5_ctx, pszNonceCount, strlen(pszNonceCount));
+ md_ctx_update(&md5_ctx, ":", 1);
+ md_ctx_update(&md5_ctx, pszCNonce, strlen(pszCNonce));
+ md_ctx_update(&md5_ctx, ":", 1);
+ md_ctx_update(&md5_ctx, pszQop, strlen(pszQop));
+ md_ctx_update(&md5_ctx, ":", 1);
+ };
+ md_ctx_update(&md5_ctx, HA2Hex, HASHHEXLEN);
+ md_ctx_final(&md5_ctx, RespHash);
+ md_ctx_cleanup(&md5_ctx);
+ CvtHex(RespHash, Response);
+}
+
+#endif