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-2010 OpenVPN Technologies, 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 20 * along with this program (see the file COPYING included with this 21 * distribution); if not, write to the Free Software Foundation, Inc., 22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 */ 24 25#ifdef HAVE_CONFIG_H 26#include "config.h" 27#elif defined(_MSC_VER) 28#include "config-msvc.h" 29#endif 30 31#include "syshead.h" 32 33#if PROXY_DIGEST_AUTH 34 35#include "crypto.h" 36#include "httpdigest.h" 37 38static void 39CvtHex( 40 IN HASH Bin, 41 OUT HASHHEX Hex 42 ) 43{ 44 unsigned short i; 45 unsigned char j; 46 47 for (i = 0; i < HASHLEN; i++) { 48 j = (Bin[i] >> 4) & 0xf; 49 if (j <= 9) 50 Hex[i*2] = (j + '0'); 51 else 52 Hex[i*2] = (j + 'a' - 10); 53 j = Bin[i] & 0xf; 54 if (j <= 9) 55 Hex[i*2+1] = (j + '0'); 56 else 57 Hex[i*2+1] = (j + 'a' - 10); 58 }; 59 Hex[HASHHEXLEN] = '\0'; 60}; 61 62/* calculate H(A1) as per spec */ 63void 64DigestCalcHA1( 65 IN char * pszAlg, 66 IN char * pszUserName, 67 IN char * pszRealm, 68 IN char * pszPassword, 69 IN char * pszNonce, 70 IN char * pszCNonce, 71 OUT HASHHEX SessionKey 72 ) 73{ 74 HASH HA1; 75 md_ctx_t md5_ctx; 76 const md_kt_t *md5_kt = md_kt_get("MD5"); 77 78 md_ctx_init(&md5_ctx, md5_kt); 79 md_ctx_update(&md5_ctx, pszUserName, strlen(pszUserName)); 80 md_ctx_update(&md5_ctx, ":", 1); 81 md_ctx_update(&md5_ctx, pszRealm, strlen(pszRealm)); 82 md_ctx_update(&md5_ctx, ":", 1); 83 md_ctx_update(&md5_ctx, pszPassword, strlen(pszPassword)); 84 md_ctx_final(&md5_ctx, HA1); 85 if (pszAlg && strcasecmp(pszAlg, "md5-sess") == 0) 86 { 87 md_ctx_init(&md5_ctx, md5_kt); 88 md_ctx_update(&md5_ctx, HA1, HASHLEN); 89 md_ctx_update(&md5_ctx, ":", 1); 90 md_ctx_update(&md5_ctx, pszNonce, strlen(pszNonce)); 91 md_ctx_update(&md5_ctx, ":", 1); 92 md_ctx_update(&md5_ctx, pszCNonce, strlen(pszCNonce)); 93 md_ctx_final(&md5_ctx, HA1); 94 }; 95 md_ctx_cleanup(&md5_ctx); 96 CvtHex(HA1, SessionKey); 97} 98 99/* calculate request-digest/response-digest as per HTTP Digest spec */ 100void 101DigestCalcResponse( 102 IN HASHHEX HA1, /* H(A1) */ 103 IN char * pszNonce, /* nonce from server */ 104 IN char * pszNonceCount, /* 8 hex digits */ 105 IN char * pszCNonce, /* client nonce */ 106 IN char * pszQop, /* qop-value: "", "auth", "auth-int" */ 107 IN char * pszMethod, /* method from the request */ 108 IN char * pszDigestUri, /* requested URL */ 109 IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */ 110 OUT HASHHEX Response /* request-digest or response-digest */ 111 ) 112{ 113 HASH HA2; 114 HASH RespHash; 115 HASHHEX HA2Hex; 116 117 md_ctx_t md5_ctx; 118 const md_kt_t *md5_kt = md_kt_get("MD5"); 119 120 /* calculate H(A2) */ 121 md_ctx_init(&md5_ctx, md5_kt); 122 md_ctx_update(&md5_ctx, pszMethod, strlen(pszMethod)); 123 md_ctx_update(&md5_ctx, ":", 1); 124 md_ctx_update(&md5_ctx, pszDigestUri, strlen(pszDigestUri)); 125 if (strcasecmp(pszQop, "auth-int") == 0) 126 { 127 md_ctx_update(&md5_ctx, ":", 1); 128 md_ctx_update(&md5_ctx, HEntity, HASHHEXLEN); 129 }; 130 md_ctx_final(&md5_ctx, HA2); 131 CvtHex(HA2, HA2Hex); 132 133 /* calculate response */ 134 md_ctx_init(&md5_ctx, md5_kt); 135 md_ctx_update(&md5_ctx, HA1, HASHHEXLEN); 136 md_ctx_update(&md5_ctx, ":", 1); 137 md_ctx_update(&md5_ctx, pszNonce, strlen(pszNonce)); 138 md_ctx_update(&md5_ctx, ":", 1); 139 if (*pszQop) 140 { 141 md_ctx_update(&md5_ctx, pszNonceCount, strlen(pszNonceCount)); 142 md_ctx_update(&md5_ctx, ":", 1); 143 md_ctx_update(&md5_ctx, pszCNonce, strlen(pszCNonce)); 144 md_ctx_update(&md5_ctx, ":", 1); 145 md_ctx_update(&md5_ctx, pszQop, strlen(pszQop)); 146 md_ctx_update(&md5_ctx, ":", 1); 147 }; 148 md_ctx_update(&md5_ctx, HA2Hex, HASHHEXLEN); 149 md_ctx_final(&md5_ctx, RespHash); 150 md_ctx_cleanup(&md5_ctx); 151 CvtHex(RespHash, Response); 152} 153 154#endif 155