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#if defined(__GNUC__) || defined(__clang__)
65#pragma GCC diagnostic push
66#pragma GCC diagnostic ignored "-Wconversion"
67#endif
68
69/* calculate H(A1) as per spec */
70void
71DigestCalcHA1(IN char *pszAlg, IN char *pszUserName, IN char *pszRealm, IN char *pszPassword,
72 IN char *pszNonce, IN char *pszCNonce, OUT HASHHEX SessionKey)
73{
74 HASH HA1;
75 md_ctx_t *md5_ctx = md_ctx_new();
76
77 md_ctx_init(md5_ctx, "MD5");
78 md_ctx_update(md5_ctx, (const uint8_t *)pszUserName, strlen(pszUserName));
79 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
80 md_ctx_update(md5_ctx, (const uint8_t *)pszRealm, strlen(pszRealm));
81 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
82 md_ctx_update(md5_ctx, (const uint8_t *)pszPassword, strlen(pszPassword));
83 md_ctx_final(md5_ctx, HA1);
84 if (pszAlg && strcasecmp(pszAlg, "md5-sess") == 0)
85 {
86 md_ctx_init(md5_ctx, "MD5");
87 md_ctx_update(md5_ctx, HA1, HASHLEN);
88 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
89 md_ctx_update(md5_ctx, (const uint8_t *)pszNonce, strlen(pszNonce));
90 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
91 md_ctx_update(md5_ctx, (const uint8_t *)pszCNonce, strlen(pszCNonce));
92 md_ctx_final(md5_ctx, HA1);
93 }
94 md_ctx_cleanup(md5_ctx);
95 md_ctx_free(md5_ctx);
96 CvtHex(HA1, SessionKey);
97}
98
99/* calculate request-digest/response-digest as per HTTP Digest spec */
100void
101DigestCalcResponse(IN HASHHEX HA1, /* H(A1) */
102 IN char *pszNonce, /* nonce from server */
103 IN char *pszNonceCount, /* 8 hex digits */
104 IN char *pszCNonce, /* client nonce */
105 IN char *pszQop, /* qop-value: "", "auth", "auth-int" */
106 IN char *pszMethod, /* method from the request */
107 IN char *pszDigestUri, /* requested URL */
108 IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
109 OUT HASHHEX Response /* request-digest or response-digest */
110)
111{
112 HASH HA2;
113 HASH RespHash;
114 HASHHEX HA2Hex;
115
116 md_ctx_t *md5_ctx = md_ctx_new();
117
118 /* calculate H(A2) */
119 md_ctx_init(md5_ctx, "MD5");
120 md_ctx_update(md5_ctx, (const uint8_t *)pszMethod, strlen(pszMethod));
121 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
122 md_ctx_update(md5_ctx, (const uint8_t *)pszDigestUri, strlen(pszDigestUri));
123 if (strcasecmp(pszQop, "auth-int") == 0)
124 {
125 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
126 md_ctx_update(md5_ctx, HEntity, HASHHEXLEN);
127 }
128 md_ctx_final(md5_ctx, HA2);
129 CvtHex(HA2, HA2Hex);
130
131 /* calculate response */
132 md_ctx_init(md5_ctx, "MD5");
133 md_ctx_update(md5_ctx, HA1, HASHHEXLEN);
134 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
135 md_ctx_update(md5_ctx, (const uint8_t *)pszNonce, strlen(pszNonce));
136 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
137 if (*pszQop)
138 {
139 md_ctx_update(md5_ctx, (const uint8_t *)pszNonceCount, strlen(pszNonceCount));
140 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
141 md_ctx_update(md5_ctx, (const uint8_t *)pszCNonce, strlen(pszCNonce));
142 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
143 md_ctx_update(md5_ctx, (const uint8_t *)pszQop, strlen(pszQop));
144 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
145 }
146 md_ctx_update(md5_ctx, HA2Hex, HASHHEXLEN);
147 md_ctx_final(md5_ctx, RespHash);
148 md_ctx_cleanup(md5_ctx);
149 md_ctx_free(md5_ctx);
150 CvtHex(RespHash, Response);
151}
152
153#if defined(__GNUC__) || defined(__clang__)
154#pragma GCC diagnostic pop
155#endif
156
157#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:71
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:101