6b2883a6 |
/*
* 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.
* |
49979459 |
* Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net> |
6b2883a6 |
*
* 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.
* |
caa54ac3 |
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
6b2883a6 |
*/
|
c110b289 |
#ifdef HAVE_CONFIG_H
#include "config.h"
#elif defined(_MSC_VER)
#include "config-msvc.h"
#endif
|
6b2883a6 |
#include "syshead.h"
#if PROXY_DIGEST_AUTH
#include "crypto.h"
#include "httpdigest.h"
static void
CvtHex( |
81d882d5 |
IN HASH Bin,
OUT HASHHEX Hex
) |
6b2883a6 |
{ |
81d882d5 |
unsigned short i;
unsigned char j; |
6b2883a6 |
|
4cd4899e |
for (i = 0; i < HASHLEN; i++)
{ |
81d882d5 |
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';
} |
6b2883a6 |
/* calculate H(A1) as per spec */
void
DigestCalcHA1( |
81d882d5 |
IN char *pszAlg,
IN char *pszUserName,
IN char *pszRealm,
IN char *pszPassword,
IN char *pszNonce,
IN char *pszCNonce,
OUT HASHHEX SessionKey
) |
6b2883a6 |
{ |
81d882d5 |
HASH HA1; |
c481ef00 |
md_ctx_t *md5_ctx = md_ctx_new(); |
81d882d5 |
const md_kt_t *md5_kt = md_kt_get("MD5"); |
6b2883a6 |
|
c481ef00 |
md_ctx_init(md5_ctx, md5_kt);
md_ctx_update(md5_ctx, (const uint8_t *) pszUserName, strlen(pszUserName));
md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
md_ctx_update(md5_ctx, (const uint8_t *) pszRealm, strlen(pszRealm));
md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
md_ctx_update(md5_ctx, (const uint8_t *) pszPassword, strlen(pszPassword));
md_ctx_final(md5_ctx, HA1); |
81d882d5 |
if (pszAlg && strcasecmp(pszAlg, "md5-sess") == 0) |
6b2883a6 |
{ |
c481ef00 |
md_ctx_init(md5_ctx, md5_kt);
md_ctx_update(md5_ctx, HA1, HASHLEN);
md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
md_ctx_update(md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce));
md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
md_ctx_update(md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce));
md_ctx_final(md5_ctx, HA1); |
81d882d5 |
} |
c481ef00 |
md_ctx_cleanup(md5_ctx);
md_ctx_free(md5_ctx); |
81d882d5 |
CvtHex(HA1, SessionKey); |
6b2883a6 |
}
/* calculate request-digest/response-digest as per HTTP Digest spec */
void
DigestCalcResponse( |
81d882d5 |
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 */
) |
6b2883a6 |
{ |
81d882d5 |
HASH HA2;
HASH RespHash;
HASHHEX HA2Hex; |
6b2883a6 |
|
c481ef00 |
md_ctx_t *md5_ctx = md_ctx_new(); |
81d882d5 |
const md_kt_t *md5_kt = md_kt_get("MD5"); |
d5f44617 |
|
81d882d5 |
/* calculate H(A2) */ |
c481ef00 |
md_ctx_init(md5_ctx, md5_kt);
md_ctx_update(md5_ctx, (const uint8_t *) pszMethod, strlen(pszMethod));
md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
md_ctx_update(md5_ctx, (const uint8_t *) pszDigestUri, strlen(pszDigestUri)); |
81d882d5 |
if (strcasecmp(pszQop, "auth-int") == 0) |
6b2883a6 |
{ |
c481ef00 |
md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
md_ctx_update(md5_ctx, HEntity, HASHHEXLEN); |
81d882d5 |
} |
c481ef00 |
md_ctx_final(md5_ctx, HA2); |
81d882d5 |
CvtHex(HA2, HA2Hex); |
6b2883a6 |
|
81d882d5 |
/* calculate response */ |
c481ef00 |
md_ctx_init(md5_ctx, md5_kt);
md_ctx_update(md5_ctx, HA1, HASHHEXLEN);
md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
md_ctx_update(md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce));
md_ctx_update(md5_ctx, (const uint8_t *) ":", 1); |
81d882d5 |
if (*pszQop) |
6b2883a6 |
{ |
c481ef00 |
md_ctx_update(md5_ctx, (const uint8_t *) pszNonceCount, strlen(pszNonceCount));
md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
md_ctx_update(md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce));
md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
md_ctx_update(md5_ctx, (const uint8_t *) pszQop, strlen(pszQop));
md_ctx_update(md5_ctx, (const uint8_t *) ":", 1); |
81d882d5 |
} |
c481ef00 |
md_ctx_update(md5_ctx, HA2Hex, HASHHEXLEN);
md_ctx_final(md5_ctx, RespHash);
md_ctx_cleanup(md5_ctx);
md_ctx_free(md5_ctx); |
81d882d5 |
CvtHex(RespHash, Response); |
6b2883a6 |
}
|
81d882d5 |
#endif /* if PROXY_DIGEST_AUTH */ |