]> www.average.org Git - pam_pcsc_cr.git/blob - authobj.c
wip to make authobj a single func
[pam_pcsc_cr.git] / authobj.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4 #include <stdio.h>
5 #include <string.h>
6 #include <alloca.h>
7 #include "serial.h"
8 #include "crypto.h"
9 #include "authobj.h"
10 #include "pcsc_cr.h"
11
12 static struct _auth_chunk
13 make_challenge(const char *uid, const char *pass, const char *nonce)
14 {
15         struct _auth_chunk ho = {0};
16         unsigned long rc;
17         serializer_t srl;
18         int datasize = strlen(uid) + strlen(pass) + strlen(nonce) +
19                         4 * sizeof(short);
20         unsigned char *data = alloca(datasize);
21         int hashsize = sizeof(ho.data);
22
23         serial_init(&srl, data, datasize);
24         if (serial_put(&srl, uid, strlen(uid)) != strlen(uid)) {
25                 ho.err = "challenge: serialization of uid failed";
26         } else if (serial_put(&srl, pass, strlen(pass)) != strlen(pass)) {
27                 ho.err = "challenge: serialization of pass failed";
28         } else if (serial_put(&srl, nonce, strlen(nonce)) != strlen(nonce)) {
29                 ho.err = "challenge: serialization of nonce failed";
30         } else if (serial_put(&srl, NULL, 0) != 0) {
31                 ho.err = "challenge: serialization of terminator failed";
32         }
33         if (!ho.err) {
34                 if ((rc = hash(data, serial_size(&srl), &ho.data, &hashsize))) {
35                         ho.err = crypto_errstr(rc);
36                 } else if (hashsize != sizeof(ho.data)) {
37                         ho.err = "challenge: hash size is wrong";
38                 }
39         }
40         memset(data, 0, datasize);
41         return ho;
42 }
43
44 static struct _auth_chunk
45 make_key(const unsigned char *challenge, const int challengesize,
46         const unsigned char *secret, const int secsize)
47 {
48         struct _auth_chunk ho = {0};
49         unsigned long rc;
50         int keysize = sizeof(ho.data);
51
52         if ((rc = hmac(secret, secsize, challenge, challengesize,
53                         &ho.data, &keysize))) {
54                 ho.err = crypto_errstr(rc);
55         } else if (keysize != sizeof(ho.data)) {
56                 ho.err = "make_key: hash size is wrong";
57         }
58         return ho;
59 }
60
61 static struct _auth_obj
62 make_authobj(char *userid, char *password, char *nonce,
63                 const unsigned char *secret, const int secsize,
64                 const unsigned char *payload, const int paylsize)
65 {
66         struct _auth_obj ao = {0};
67         unsigned long rc;
68         unsigned char *data;
69         int datasize;
70         unsigned char datahash[HASHSIZE];
71         int datahashsize = HASHSIZE;
72         serializer_t srl;
73
74         if (keysize < CBLKSIZE) {
75                 ao.err = "make authobj: key too short";
76                 return ao;
77         }
78         datasize = ((secsize + paysize + HASHSIZE + 4 * sizeof(short) - 1) /
79                         CBLKSIZE + 1) * CBLKSIZE;
80         data = alloca(datasize);
81         serial_init(&srl, data, datasize);
82         if (serial_put(&srl, secret, secsize) != secsize) {
83                 ao.err = "authobj: serialization of secret failed";
84         } else if (serial_put(&srl, payload, paysize) != paysize) {
85                 ao.err = "authobj: serialization of payload failed";
86         } else if ((rc = hash(data, serial_size(&srl),
87                                 datahash, &datahashsize))) {
88                 ao.err = crypto_errstr(rc);
89         } else if (serial_put(&srl, datahash, datahashsize) != datahashsize) {
90                 ao.err = "authobj: serialization of hash failed";
91         } else if (serial_put(&srl, NULL, 0) != 0) {
92                 ao.err = "authobj: serialization of terminator failed";
93         }
94
95         if (!ao.err) {
96                 unsigned long lrc;
97                 int osize = ((serial_size(&srl) -1) / CBLKSIZE + 1) * CBLKSIZE;
98
99                 if ((ao.buffer = malloc(osize + paysize)) == NULL) {
100                         ao.err = "make authobj: malloc failed";
101                 } else if ((lrc = encrypt(key, CBLKSIZE, data,
102                                         ao.buffer, osize))) {
103                         ao.err = crypto_errstr(lrc);
104                 } else {
105                         ao.data = ao.buffer;
106                         ao.datasize = osize;
107                         if (payload && paysize) {
108                                 /* payload passthrough */
109                                 ao.payload = ao.data + osize;
110                                 memcpy(ao.payload, payload, paysize);
111                                 ao.paylsize = paysize;
112                         }
113                 }
114         }
115
116         memset(data, 0, datasize);
117         return ao;
118 }
119
120 static struct _auth_obj
121 parse_authobj(char *userid, char *password, char *nonce,
122                 const unsigned char *secret, const int secsize,
123                 const unsigned char *ablob, const int blobsize,
124                 struct _auth_chunk (*fetch_key)(const unsigned char *chal,
125                                                 const int csize))
126 {
127         unsigned long rc;
128         struct _auth_obj ao = {0};
129
130         if (keysize < CBLKSIZE) {
131                 ao.err = "parse authobj: key too short";
132         } else if ((ao.buffer = malloc(bufsize)) == NULL) {
133                 ao.err = "parse authobj: malloc failed";
134         } else if ((rc = decrypt(key, CBLKSIZE, buffer, ao.buffer, bufsize))) {
135                 ao.err = crypto_errstr(rc);
136         } else {
137                 serializer_t srl;
138                 unsigned char myhash[HASHSIZE];
139                 int myhsize = HASHSIZE;
140                 unsigned char *theirhash;
141                 int theirhsize;
142                 unsigned long rc;
143
144                 serial_init(&srl, ao.buffer, bufsize);
145                 if (serial_get(&srl, (void**)&ao.data, &ao.datasize)) {
146                         ao.err = "mismatch: impossible secret";
147                 } else if (serial_get(&srl, (void**)&ao.payload, &ao.paylsize)) {
148                         ao.err = "mismatch: impossible payload";
149                 } else if ((rc = hash(ao.buffer, serial_size(&srl),
150                                         myhash, &myhsize))) {
151                         ao.err = crypto_errstr(rc);
152                 } else if (serial_get(&srl, (void**)&theirhash, &theirhsize)) {
153                         ao.err = "mismatch: impossible hash";
154                 } else if (theirhsize != HASHSIZE) {
155                         ao.err = "mismatch: hash is of wrong size";
156                 } else if ((myhsize != theirhsize) ||
157                                 memcmp(myhash, theirhash, myhsize)) {
158                         ao.err = "mismatch: different hash";
159                 }
160         }
161         return ao;
162 }
163
164 struct _auth_obj authobj(const char *userid, const char *password,
165                 const char *oldnonce, const char *newnonce,
166                 const unsigned char *secret, const int secsize,
167                 const unsigned char *payload, const int paylsize,
168                 const unsigned char *ablob, const int blobsize,
169                 struct _auth_chunk (*fetch_key)(const unsigned char *chal,
170                                                 const int csize))
171 {
172         unsigned char *wsecret;
173         int wsecsize;
174         unsigned char *wpayload;
175         int wpaylsize;
176         struct _auth_obj old_ao;
177         struct _auth_obj new_ao = {0};
178
179         if (!secret || !secsize || !payload) {
180                 old_ao = parse_authobj(userid, password, oldnonce,
181                                         secret, secsize,
182                                         ablob, blobsize, fetch_key);
183                 if (old_ao.err) {
184                         new_ao.err = old_ao.err;
185                         if (old_ao.buffer) free(old_ao.buffer);
186                         return new_ao;
187                 } else {
188                         if (secret && secsize) {
189                                 wsecret = secret;
190                                 wsecsize = secsize;
191                         } else {
192                                 wsecret = old_ao.data;
193                                 wsecsize = old_ao.datasize;
194                         }
195                         if (payload) {
196                                 wpayload = payload;
197                                 wpaylsize = paylsize;
198                         } else {
199                                 wpayload = old_ao.payload;
200                                 wpaylsize = old_ao.paylsize;
201                         }
202                 }
203         } else {
204                 wsecret = secret;
205                 wsecsize = secsize;
206                 wpayload = payload;
207                 wpaylsize = paylsize;
208         }
209
210
211         new_ao = make_authobj(userid, password, newnonce,
212                                 wsecret, wsecsize, wpayload, wpaysize);
213
214         if (old_ao.data) memset(old_ao.data, 0, old_ao.datasize);
215         if (old_ao.payload) memset(old_ao.payload, 0, old_ao.paylsize);
216         if (old_ao.buffer) free(old_ao.buffer);
217         return new_ao;
218 }
219
220 void dummy() {
221         struct _auth_chunk ho_chal, ho_key;
222
223         ho_chal = make_challenge(userid, password, oldnonce);
224         if (ho_chal.err) {
225                 new_ao.err = ho_chal.err;
226                 return new_ao;
227         }
228         ho_key = (*fetch_key)(ho_chal.hash, sizeof(ho_chal.hash));
229         memset(&ho_chal, 0, sizeof(ho_chal));
230         if (ho_key.err) {
231                 new_ao.err = ho_key.err;
232                 return new_ao;
233         }
234         old_ao = parse_authobj(ho_key.hash, sizeof(ho_key.hash),
235                                 authobj, authsize);
236         memset(&ho_key, 0, sizeof(ho_key));
237         if (old_ao.err) {
238                 new_ao.err = old_ao.err;
239                 if (old_ao.buffer) free(old_ao.buffer);
240                 return new_ao;
241         }
242
243         ho_chal = make_challenge(userid, password, newnonce);
244         if (ho_chal.err) {
245                 new_ao.err = ho_chal.err;
246                 return new_ao;
247         }
248         ho_key = make_key(ho_chal.hash, sizeof(ho_chal.hash),
249                                 old_ao.data, old_ao.datasize);
250         memset(&ho_chal, 0, sizeof(ho_chal));
251         if (ho_key.err) {
252                 new_ao.err = ho_key.err;
253                 return new_ao;
254         }
255         new_ao = make_authobj(ho_key.hash, sizeof(ho_key.hash),
256                         old_ao.data, old_ao.datasize,
257                         old_ao.payload, old_ao.paylsize);
258         memset(&ho_key, 0, sizeof(ho_key));
259
260 }