Commit | Line | Data |
---|---|---|
e4169f77 JVH |
1 | #include <stdlib.h> |
2 | #include <stdio.h> | |
3 | #include <stdint.h> | |
4 | #include <string.h> | |
5 | ||
6 | #include "compat.h" | |
7 | #include "utils.h" | |
8 | #include "crypto/crypto.h" | |
9 | ||
10 | void | |
11 | digest_md5_to_hex(const unsigned char *md5buf, char *md5hex) | |
12 | { | |
13 | int i; | |
14 | for (i=0; i<MD5_SIZE*2; i++) { | |
15 | int val = (i%2) ? md5buf[i/2]&0x0f : (md5buf[i/2]&0xf0)>>4; | |
16 | md5hex[i] = (val<10) ? '0'+val : 'a'+(val-10); | |
17 | } | |
18 | } | |
19 | ||
20 | void | |
21 | digest_get_response(const char *username, const char *realm, | |
22 | const char *password, const char *nonce, | |
23 | const char *method, const char *uri, | |
24 | char *response) | |
25 | { | |
26 | MD5_CTX md5ctx; | |
27 | unsigned char md5buf[MD5_SIZE]; | |
28 | char md5hex[MD5_SIZE*2]; | |
29 | ||
30 | /* Calculate first inner MD5 hash */ | |
31 | MD5_Init(&md5ctx); | |
32 | MD5_Update(&md5ctx, (const unsigned char *)username, strlen(username)); | |
33 | MD5_Update(&md5ctx, (const unsigned char *)":", 1); | |
34 | MD5_Update(&md5ctx, (const unsigned char *)realm, strlen(realm)); | |
35 | MD5_Update(&md5ctx, (const unsigned char *)":", 1); | |
36 | MD5_Update(&md5ctx, (const unsigned char *)password, strlen(password)); | |
37 | MD5_Final(md5buf, &md5ctx); | |
38 | digest_md5_to_hex(md5buf, md5hex); | |
39 | ||
40 | /* Calculate second inner MD5 hash */ | |
41 | MD5_Init(&md5ctx); | |
42 | MD5_Update(&md5ctx, (const unsigned char *)method, strlen(method)); | |
43 | MD5_Update(&md5ctx, (const unsigned char *)":", 1); | |
44 | MD5_Update(&md5ctx, (const unsigned char *)uri, strlen(uri)); | |
45 | MD5_Final(md5buf, &md5ctx); | |
46 | ||
47 | /* Calculate outer MD5 hash */ | |
48 | MD5_Init(&md5ctx); | |
49 | MD5_Update(&md5ctx, (const unsigned char *)md5hex, sizeof(md5hex)); | |
50 | MD5_Update(&md5ctx, (const unsigned char *)":", 1); | |
51 | MD5_Update(&md5ctx, (const unsigned char *)nonce, strlen(nonce)); | |
52 | MD5_Update(&md5ctx, (const unsigned char *)":", 1); | |
53 | digest_md5_to_hex(md5buf, md5hex); | |
54 | MD5_Update(&md5ctx, (const unsigned char *)md5hex, sizeof(md5hex)); | |
55 | MD5_Final(md5buf, &md5ctx); | |
56 | ||
57 | /* Store the final result to response */ | |
58 | digest_md5_to_hex(md5buf, response); | |
59 | } | |
60 | ||
61 | void | |
62 | digest_generate_nonce(char *result, int resultlen) | |
63 | { | |
64 | MD5_CTX md5ctx; | |
65 | unsigned char md5buf[MD5_SIZE]; | |
66 | char md5hex[MD5_SIZE*2]; | |
67 | unsigned int time; | |
68 | ||
69 | SYSTEM_GET_TIME(time); | |
70 | ||
71 | MD5_Init(&md5ctx); | |
72 | MD5_Update(&md5ctx, (unsigned char *)&time, sizeof(time)); | |
73 | MD5_Final(md5buf, &md5ctx); | |
74 | digest_md5_to_hex(md5buf, md5hex); | |
75 | ||
268f72c8 | 76 | memset(result, 0, resultlen); |
e4169f77 | 77 | strncpy(result, md5hex, resultlen-1); |
e4169f77 JVH |
78 | } |
79 | ||
80 | int | |
81 | digest_is_valid(const char *our_realm, const char *password, | |
82 | const char *our_nonce, const char *method, | |
268f72c8 | 83 | const char *our_uri, const char *authorization) |
e4169f77 JVH |
84 | { |
85 | char *auth; | |
86 | char *current; | |
87 | char *value; | |
88 | int success; | |
89 | ||
90 | /* Get values from authorization */ | |
91 | char *username = NULL; | |
92 | char *realm = NULL; | |
93 | char *nonce = NULL; | |
94 | char *uri = NULL; | |
95 | char *response = NULL; | |
96 | ||
97 | /* Buffer for our response */ | |
98 | char our_response[MD5_SIZE*2+1]; | |
99 | ||
100 | if (!authorization) { | |
101 | return 0; | |
102 | } | |
103 | current = auth = strdup(authorization); | |
104 | if (!auth) { | |
105 | return 0; | |
106 | } | |
107 | ||
108 | /* Check that the type is digest */ | |
109 | if (strncmp("Digest", current, 6)) { | |
110 | free(auth); | |
111 | return 0; | |
112 | } | |
113 | current += 6; | |
114 | ||
115 | while ((value = utils_strsep(¤t, ",")) != NULL) { | |
116 | char *first, *last; | |
117 | ||
118 | /* Find first and last characters */ | |
119 | first = value; | |
120 | last = value+strlen(value)-1; | |
121 | ||
122 | /* Trim spaces from the value */ | |
123 | while (*first == ' ' && first < last) first++; | |
124 | while (*last == ' ' && last > first) last--; | |
125 | ||
126 | /* Validate the last character */ | |
127 | if (*last != '"') continue; | |
128 | else *last = '\0'; | |
129 | ||
130 | /* Store value if it is relevant */ | |
131 | if (!strncmp("username=\"", first, 10)) | |
132 | username = first+10; | |
133 | if (!strncmp("realm=\"", first, 7)) | |
134 | realm = first+7; | |
135 | if (!strncmp("nonce=\"", first, 7)) | |
136 | nonce = first+7; | |
137 | if (!strncmp("uri=\"", first, 5)) | |
138 | uri = first+5; | |
139 | if (!strncmp("response=\"", first, 10)) | |
140 | response = first+10; | |
141 | } | |
142 | ||
268f72c8 | 143 | if (!username || !realm || !nonce || !uri || !response) { |
06582fec | 144 | free(auth); |
268f72c8 JVH |
145 | return 0; |
146 | } | |
147 | if (strcmp(realm, our_realm) || strcmp(nonce, our_nonce) || strcmp(uri, our_uri)) { | |
06582fec | 148 | free(auth); |
268f72c8 JVH |
149 | return 0; |
150 | } | |
151 | ||
e4169f77 JVH |
152 | /* Calculate our response */ |
153 | memset(our_response, 0, sizeof(our_response)); | |
154 | digest_get_response(username, realm, password, nonce, | |
155 | method, uri, our_response); | |
156 | success = !strcmp(response, our_response); | |
157 | free(auth); | |
158 | ||
159 | return success; | |
160 | } | |
161 | ||
162 |