diff options
Diffstat (limited to 'src/openvpn/httpdigest.c')
-rw-r--r-- | src/openvpn/httpdigest.c | 154 |
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 |