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-2026 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 for (unsigned short i = 0; i < HASHLEN; i++)
38 {
39 unsigned char j = (Bin[i] >> 4) & 0xf;
40 if (j <= 9)
41 {
42 Hex[i * 2] = (j + '0');
43 }
44 else
45 {
46 Hex[i * 2] = (unsigned char)(j + 'a' - 10);
47 }
48 j = Bin[i] & 0xf;
49 if (j <= 9)
50 {
51 Hex[i * 2 + 1] = (j + '0');
52 }
53 else
54 {
55 Hex[i * 2 + 1] = (unsigned char)(j + 'a' - 10);
56 }
57 }
58 Hex[HASHHEXLEN] = '\0';
59}
60
61/* calculate H(A1) as per spec */
62void
63DigestCalcHA1(IN char *pszAlg, IN char *pszUserName, IN char *pszRealm, IN char *pszPassword,
64 IN char *pszNonce, IN char *pszCNonce, OUT HASHHEX SessionKey)
65{
66 HASH HA1;
67 md_ctx_t *md5_ctx = md_ctx_new();
68
69 md_ctx_init(md5_ctx, "MD5");
70 md_ctx_update(md5_ctx, (const uint8_t *)pszUserName, strlen(pszUserName));
71 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
72 md_ctx_update(md5_ctx, (const uint8_t *)pszRealm, strlen(pszRealm));
73 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
74 md_ctx_update(md5_ctx, (const uint8_t *)pszPassword, strlen(pszPassword));
75 md_ctx_final(md5_ctx, HA1);
76 if (pszAlg && strcasecmp(pszAlg, "md5-sess") == 0)
77 {
78 md_ctx_init(md5_ctx, "MD5");
79 md_ctx_update(md5_ctx, HA1, HASHLEN);
80 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
81 md_ctx_update(md5_ctx, (const uint8_t *)pszNonce, strlen(pszNonce));
82 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
83 md_ctx_update(md5_ctx, (const uint8_t *)pszCNonce, strlen(pszCNonce));
84 md_ctx_final(md5_ctx, HA1);
85 }
86 md_ctx_cleanup(md5_ctx);
87 md_ctx_free(md5_ctx);
88 CvtHex(HA1, SessionKey);
89}
90
91/* calculate request-digest/response-digest as per HTTP Digest spec */
92void
93DigestCalcResponse(IN HASHHEX HA1, /* H(A1) */
94 IN char *pszNonce, /* nonce from server */
95 IN char *pszNonceCount, /* 8 hex digits */
96 IN char *pszCNonce, /* client nonce */
97 IN char *pszQop, /* qop-value: "", "auth", "auth-int" */
98 IN char *pszMethod, /* method from the request */
99 IN char *pszDigestUri, /* requested URL */
100 IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
101 OUT HASHHEX Response /* request-digest or response-digest */
102)
103{
104 HASH HA2;
105 HASH RespHash;
106 HASHHEX HA2Hex;
107
108 md_ctx_t *md5_ctx = md_ctx_new();
109
110 /* calculate H(A2) */
111 md_ctx_init(md5_ctx, "MD5");
112 md_ctx_update(md5_ctx, (const uint8_t *)pszMethod, strlen(pszMethod));
113 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
114 md_ctx_update(md5_ctx, (const uint8_t *)pszDigestUri, strlen(pszDigestUri));
115 if (strcasecmp(pszQop, "auth-int") == 0)
116 {
117 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
118 md_ctx_update(md5_ctx, HEntity, HASHHEXLEN);
119 }
120 md_ctx_final(md5_ctx, HA2);
121 CvtHex(HA2, HA2Hex);
122
123 /* calculate response */
124 md_ctx_init(md5_ctx, "MD5");
125 md_ctx_update(md5_ctx, HA1, HASHHEXLEN);
126 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
127 md_ctx_update(md5_ctx, (const uint8_t *)pszNonce, strlen(pszNonce));
128 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
129 if (*pszQop)
130 {
131 md_ctx_update(md5_ctx, (const uint8_t *)pszNonceCount, strlen(pszNonceCount));
132 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
133 md_ctx_update(md5_ctx, (const uint8_t *)pszCNonce, strlen(pszCNonce));
134 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
135 md_ctx_update(md5_ctx, (const uint8_t *)pszQop, strlen(pszQop));
136 md_ctx_update(md5_ctx, (const uint8_t *)":", 1);
137 }
138 md_ctx_update(md5_ctx, HA2Hex, HASHHEXLEN);
139 md_ctx_final(md5_ctx, RespHash);
140 md_ctx_cleanup(md5_ctx);
141 md_ctx_free(md5_ctx);
142 CvtHex(RespHash, Response);
143}
144
145#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, size_t 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)
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:63
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:93