5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
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.
22 #include "silcincludes.h"
25 /******************************************************************************
27 Authentication Payload
29 ******************************************************************************/
31 /* Authentication Payload structure */
32 struct SilcAuthPayloadStruct {
34 unsigned short auth_method;
35 unsigned short random_len;
36 unsigned char *random_data;
37 unsigned short auth_len;
38 unsigned char *auth_data;
41 /* Parses and returns Authentication Payload */
43 SilcAuthPayload silc_auth_payload_parse(SilcBuffer buffer)
48 SILC_LOG_DEBUG(("Parsing Authentication Payload"));
50 new = silc_calloc(1, sizeof(*new));
52 /* Parse the payload */
53 ret = silc_buffer_unformat(buffer,
54 SILC_STR_UI_SHORT(&new->len),
55 SILC_STR_UI_SHORT(&new->auth_method),
56 SILC_STR_UI16_NSTRING_ALLOC(&new->random_data,
58 SILC_STR_UI16_NSTRING_ALLOC(&new->auth_data,
66 if (new->len != buffer->len) {
67 silc_auth_payload_free(new);
71 /* If password authentication, random data must not be set */
72 if (new->auth_method == SILC_AUTH_PASSWORD && new->random_len) {
73 silc_auth_payload_free(new);
80 /* Encodes authentication payload into buffer and returns it */
82 SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
83 unsigned char *random_data,
84 unsigned short random_len,
85 unsigned char *auth_data,
86 unsigned short auth_len)
91 SILC_LOG_DEBUG(("Encoding Authentication Payload"));
93 len = 4 + 4 + random_len + auth_len;
94 buffer = silc_buffer_alloc(len);
95 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
96 silc_buffer_format(buffer,
97 SILC_STR_UI_SHORT(len),
98 SILC_STR_UI_SHORT(method),
99 SILC_STR_UI_SHORT(random_len),
100 SILC_STR_UI_XNSTRING(random_data, random_len),
101 SILC_STR_UI_SHORT(auth_len),
102 SILC_STR_UI_XNSTRING(auth_data, auth_len),
108 /* Frees authentication payload. */
110 void silc_auth_payload_free(SilcAuthPayload payload)
113 if (payload->random_data) {
114 memset(payload->random_data, 0, payload->random_len);
115 silc_free(payload->random_data);
117 if (payload->auth_data) {
118 memset(payload->auth_data, 0, payload->auth_len);
119 silc_free(payload->auth_data);
125 /******************************************************************************
127 Authentication Routines
129 ******************************************************************************/
131 /* Encodes the authentication data for hashing and signing as the protocol
134 static unsigned char *
135 silc_auth_public_key_encode_data(SilcPublicKey public_key,
136 unsigned char *random,
137 unsigned int random_len, void *id,
138 SilcIdType type, unsigned int *ret_len)
141 unsigned char *pk, *id_data, *ret;
142 unsigned int pk_len, id_len;
144 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
148 id_data = silc_id_id2str(id, type);
153 id_len = silc_id_get_len(type);
155 buf = silc_buffer_alloc(random_len + pk_len);
156 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
157 silc_buffer_format(buf,
158 SILC_STR_UI_XNSTRING(random, random_len),
159 SILC_STR_UI_XNSTRING(id_data, id_len),
160 SILC_STR_UI_XNSTRING(pk, pk_len),
163 ret = silc_calloc(buf->len, sizeof(*ret));
164 memcpy(ret, buf->data, buf->len);
169 silc_buffer_free(buf);
176 /* Generates Authentication Payload with authentication data. This is used
177 to do public key based authentication. This generates the random data
178 and the actual authentication data. Returns NULL on error. */
180 SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
182 void *id, SilcIdType type)
184 unsigned char *random;
185 unsigned char auth_data[32];
186 unsigned int auth_len;
188 unsigned int tmp_len;
192 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
194 /* Get 256 bytes of random data */
195 random = silc_rng_global_get_rn_data(256);
199 /* Encode the auth data */
200 tmp = silc_auth_public_key_encode_data(public_key, random, 256, id, type,
205 /* Allocate PKCS object */
206 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
207 memset(tmp, 0, tmp_len);
212 /* Compute the hash and the signature. */
213 if (!silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
215 memset(random, 0, 256);
216 memset(tmp, 0, tmp_len);
219 silc_pkcs_free(pkcs);
223 /* Encode Authentication Payload */
224 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, random, 256,
225 auth_data, auth_len);
227 memset(tmp, 0, tmp_len);
228 memset(auth_data, 0, sizeof(auth_data));
229 memset(random, 0, 256);
232 silc_pkcs_free(pkcs);
237 /* Verifies the authentication data. Returns TRUE if authentication was
240 int silc_auth_public_key_auth_verify(SilcAuthPayload payload,
241 SilcPublicKey public_key, SilcHash hash,
242 void *id, SilcIdType type)
245 unsigned int tmp_len;
248 SILC_LOG_DEBUG(("Verifying authentication data"));
250 /* Encode auth data */
251 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
255 SILC_LOG_DEBUG(("Authentication failed"));
259 /* Allocate PKCS object */
260 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
261 memset(tmp, 0, tmp_len);
266 /* Verify the authentication data */
267 if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
268 payload->auth_len, tmp, tmp_len)) {
270 memset(tmp, 0, tmp_len);
272 silc_pkcs_free(pkcs);
273 SILC_LOG_DEBUG(("Authentication failed"));
277 memset(tmp, 0, tmp_len);
279 silc_pkcs_free(pkcs);
281 SILC_LOG_DEBUG(("Authentication successfull"));
286 /* Same as above but the payload is not parsed yet. This will parse it. */
288 int silc_auth_public_key_auth_verify_data(SilcBuffer payload,
289 SilcPublicKey public_key,
291 void *id, SilcIdType type)
293 SilcAuthPayload auth_payload;
296 auth_payload = silc_auth_payload_parse(payload);
298 SILC_LOG_DEBUG(("Authentication failed"));
302 ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
305 silc_auth_payload_free(auth_payload);
310 /* Verifies the authentication data directly from the Authentication
311 Payload. Supports all authentication methods. If the authentication
312 method is passphrase based then the `auth_data' and `auth_data_len'
313 are the passphrase and its length. If the method is public key
314 authentication then the `auth_data' is the SilcPublicKey and the
315 `auth_data_len' is ignored. */
317 int silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
318 void *auth_data, unsigned int auth_data_len,
319 SilcHash hash, void *id, SilcIdType type)
321 SILC_LOG_DEBUG(("Verifying authentication"));
323 if (auth_method != payload->auth_method)
326 switch (payload->auth_method) {
328 /* No authentication */
329 SILC_LOG_DEBUG(("No authentication required"));
332 case SILC_AUTH_PASSWORD:
333 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
334 arguments are not needed. */
335 if (!memcmp(payload->auth_data, auth_data, payload->auth_len)) {
336 SILC_LOG_DEBUG(("Authentication successfull"));
341 case SILC_AUTH_PUBLIC_KEY:
342 /* Public key based authentication */
343 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
351 SILC_LOG_DEBUG(("Authentication failed"));
356 /* Same as above but parses the authentication payload before verify. */
358 int silc_auth_verify_data(unsigned char *payload, unsigned int payload_len,
359 SilcAuthMethod auth_method, void *auth_data,
360 unsigned int auth_data_len, SilcHash hash,
361 void *id, SilcIdType type)
363 SilcAuthPayload auth_payload;
367 buffer = silc_buffer_alloc(payload_len);
368 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
369 silc_buffer_put(buffer, payload, payload_len);
370 auth_payload = silc_auth_payload_parse(buffer);
372 silc_buffer_free(buffer);
376 ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
379 silc_auth_payload_free(auth_payload);
380 silc_buffer_free(buffer);
385 /******************************************************************************
387 Key Agreement Payload
389 ******************************************************************************/
391 /* The Key Agreement protocol structure */
392 struct SilcKeyAgreementPayloadStruct {
393 unsigned short hostname_len;
394 unsigned char *hostname;
398 /* Parses and returns an allocated Key Agreement payload. */
400 SilcKeyAgreementPayload silc_key_agreement_payload_parse(SilcBuffer buffer)
402 SilcKeyAgreementPayload new;
405 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
407 new = silc_calloc(1, sizeof(*new));
409 /* Parse the payload */
410 ret = silc_buffer_unformat(buffer,
411 SILC_STR_UI16_NSTRING_ALLOC(&new->hostname,
413 SILC_STR_UI_INT(&new->port),
423 /* Encodes the Key Agreement protocol and returns the encoded buffer */
425 SilcBuffer silc_key_agreement_payload_encode(char *hostname,
429 unsigned int len = hostname ? strlen(hostname) : 0;
431 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
433 buffer = silc_buffer_alloc(2 + len + 4);
434 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
435 silc_buffer_format(buffer,
436 SILC_STR_UI_SHORT(len),
437 SILC_STR_UI_XNSTRING(hostname, len),
438 SILC_STR_UI_INT(port),
444 /* Frees the Key Agreement protocol */
446 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
449 silc_free(payload->hostname);
454 /* Returns the hostname in the payload */
456 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
458 return payload->hostname;
461 /* Returns the port in the payload */
463 unsigned int silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
465 return payload->port;