OpenVPN
httpdigest.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2002-2025 OpenVPN Inc <sales@openvpn.net>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, see <https://www.gnu.org/licenses/>.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include "syshead.h"
28
29#if PROXY_DIGEST_AUTH
30
31#include "crypto.h"
32#include "httpdigest.h"
33
34static void
35CvtHex(IN HASH Bin, OUT HASHHEX Hex)
36{
37 unsigned short i;
38 unsigned char j;
39
40 for (i = 0; i < HASHLEN; i++)
41 {
42 j = (Bin[i] >> 4) & 0xf;
43 if (j <= 9)
44 {
45 Hex[i * 2] = (j + '0');
46 }
47 else
48 {
49 Hex[i * 2] = (j + 'a' - 10);
50 }
51 j = Bin[i] & 0xf;
52 if (j <= 9)
53 {
54 Hex[i * 2 + 1] = (j + '0');
55 }
56 else
57 {
58 Hex[i * 2 + 1] = (j + 'a' - 10);
59 }
60 }
61 Hex[HASHHEXLEN] = '\0';
62}
63
64/* calculate H(A1) as per spec */
65void
66DigestCalcHA1(IN char *pszAlg, IN char *pszUserName, IN char *pszRealm, IN char *pszPassword,
67 IN char *pszNonce, IN char *pszCNonce, OUT HASHHEX SessionKey)
68{
69 HASH HA1;
70 md_ctx_t *md5_ctx = md_ctx_new();
71
72 md_ctx_init(md5_ctx, "MD5");
73 md_ctx_update(md5_ctx, (const uint8_t *)pszUserName, strlen(pszUserName));
74 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
75 md_ctx_update(md5_ctx, (const uint8_t *)pszRealm, strlen(pszRealm));
76 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
77 md_ctx_update(md5_ctx, (const uint8_t *)pszPassword, strlen(pszPassword));
78 md_ctx_final(md5_ctx, HA1);
79 if (pszAlg && strcasecmp(pszAlg, "md5-sess") == 0)
80 {
81 md_ctx_init(md5_ctx, "MD5");
82 md_ctx_update(md5_ctx, HA1, HASHLEN);
83 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
84 md_ctx_update(md5_ctx, (const uint8_t *)pszNonce, strlen(pszNonce));
85 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
86 md_ctx_update(md5_ctx, (const uint8_t *)pszCNonce, strlen(pszCNonce));
87 md_ctx_final(md5_ctx, HA1);
88 }
89 md_ctx_cleanup(md5_ctx);
90 md_ctx_free(md5_ctx);
91 CvtHex(HA1, SessionKey);
92}
93
94/* calculate request-digest/response-digest as per HTTP Digest spec */
95void
96DigestCalcResponse(IN HASHHEX HA1, /* H(A1) */
97 IN char *pszNonce, /* nonce from server */
98 IN char *pszNonceCount, /* 8 hex digits */
99 IN char *pszCNonce, /* client nonce */
100 IN char *pszQop, /* qop-value: "", "auth", "auth-int" */
101 IN char *pszMethod, /* method from the request */
102 IN char *pszDigestUri, /* requested URL */
103 IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
104 OUT HASHHEX Response /* request-digest or response-digest */
105)
106{
107 HASH HA2;
108 HASH RespHash;
109 HASHHEX HA2Hex;
110
111 md_ctx_t *md5_ctx = md_ctx_new();
112
113 /* calculate H(A2) */
114 md_ctx_init(md5_ctx, "MD5");
115 md_ctx_update(md5_ctx, (const uint8_t *)pszMethod, strlen(pszMethod));
116 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
117 md_ctx_update(md5_ctx, (const uint8_t *)pszDigestUri, strlen(pszDigestUri));
118 if (strcasecmp(pszQop, "auth-int") == 0)
119 {
120 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
121 md_ctx_update(md5_ctx, HEntity, HASHHEXLEN);
122 }
123 md_ctx_final(md5_ctx, HA2);
124 CvtHex(HA2, HA2Hex);
125
126 /* calculate response */
127 md_ctx_init(md5_ctx, "MD5");
128 md_ctx_update(md5_ctx, HA1, HASHHEXLEN);
129 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
130 md_ctx_update(md5_ctx, (const uint8_t *)pszNonce, strlen(pszNonce));
131 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
132 if (*pszQop)
133 {
134 md_ctx_update(md5_ctx, (const uint8_t *)pszNonceCount, strlen(pszNonceCount));
135 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
136 md_ctx_update(md5_ctx, (const uint8_t *)pszCNonce, strlen(pszCNonce));
137 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
138 md_ctx_update(md5_ctx, (const uint8_t *)pszQop, strlen(pszQop));
139 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
140 }
141 md_ctx_update(md5_ctx, HA2Hex, HASHHEXLEN);
142 md_ctx_final(md5_ctx, RespHash);
143 md_ctx_cleanup(md5_ctx);
144 md_ctx_free(md5_ctx);
145 CvtHex(RespHash, Response);
146}
147
148#endif /* if PROXY_DIGEST_AUTH */
Data Channel Cryptography Module.
md_ctx_t * md_ctx_new(void)
void md_ctx_update(md_ctx_t *ctx, const uint8_t *src, int src_len)
void md_ctx_cleanup(md_ctx_t *ctx)
void md_ctx_final(md_ctx_t *ctx, uint8_t *dst)
void md_ctx_init(md_ctx_t *ctx, const char *mdname)
Initialises the given message digest context.
void md_ctx_free(md_ctx_t *ctx)
mbedtls_md_context_t md_ctx_t
Generic message digest context.
void DigestCalcHA1(IN char *pszAlg, IN char *pszUserName, IN char *pszRealm, IN char *pszPassword, IN char *pszNonce, IN char *pszCNonce, OUT HASHHEX SessionKey)
Definition httpdigest.c:66
static void CvtHex(IN HASH Bin, OUT HASHHEX Hex)
Definition httpdigest.c:35
void DigestCalcResponse(IN HASHHEX HA1, IN char *pszNonce, IN char *pszNonceCount, IN char *pszCNonce, IN char *pszQop, IN char *pszMethod, IN char *pszDigestUri, IN HASHHEX HEntity, OUT HASHHEX Response)
Definition httpdigest.c:96