5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2002 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 SilcUInt16 auth_method;
35 SilcUInt16 random_len;
36 unsigned char *random_data;
38 unsigned char *auth_data;
41 /* Parses and returns Authentication Payload */
43 SilcAuthPayload silc_auth_payload_parse(const unsigned char *data,
46 SilcBufferStruct buffer;
50 SILC_LOG_DEBUG(("Parsing Authentication Payload"));
52 silc_buffer_set(&buffer, (unsigned char *)data, data_len);
53 newp = silc_calloc(1, sizeof(*newp));
57 /* Parse the payload */
58 ret = silc_buffer_unformat(&buffer,
59 SILC_STR_UI_SHORT(&newp->len),
60 SILC_STR_UI_SHORT(&newp->auth_method),
61 SILC_STR_UI16_NSTRING_ALLOC(&newp->random_data,
63 SILC_STR_UI16_NSTRING_ALLOC(&newp->auth_data,
71 if (newp->len != buffer.len) {
72 silc_auth_payload_free(newp);
76 /* Authentication data must be provided */
77 if (newp->auth_len < 1) {
78 silc_auth_payload_free(newp);
82 /* If password authentication, random data must not be set */
83 if (newp->auth_method == SILC_AUTH_PASSWORD && newp->random_len) {
84 silc_auth_payload_free(newp);
88 /* If public key authentication, random data must be at least 128 bytes */
89 if (newp->auth_method == SILC_AUTH_PUBLIC_KEY && newp->random_len < 128) {
90 silc_auth_payload_free(newp);
97 /* Encodes authentication payload into buffer and returns it */
99 SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
100 const unsigned char *random_data,
101 SilcUInt16 random_len,
102 const unsigned char *auth_data,
108 SILC_LOG_DEBUG(("Encoding Authentication Payload"));
110 len = 2 + 2 + 2 + random_len + 2 + auth_len;
111 buffer = silc_buffer_alloc_size(len);
114 silc_buffer_format(buffer,
115 SILC_STR_UI_SHORT(len),
116 SILC_STR_UI_SHORT(method),
117 SILC_STR_UI_SHORT(random_len),
118 SILC_STR_UI_XNSTRING(random_data, random_len),
119 SILC_STR_UI_SHORT(auth_len),
120 SILC_STR_UI_XNSTRING(auth_data, auth_len),
126 /* Frees authentication payload. */
128 void silc_auth_payload_free(SilcAuthPayload payload)
131 if (payload->random_data) {
132 memset(payload->random_data, 0, payload->random_len);
133 silc_free(payload->random_data);
135 if (payload->auth_data) {
136 memset(payload->auth_data, 0, payload->auth_len);
137 silc_free(payload->auth_data);
143 /* Get authentication method */
145 SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload)
147 return payload->auth_method;
150 /* Get the authentication data */
152 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
153 SilcUInt32 *auth_len)
156 *auth_len = payload->auth_len;
158 return payload->auth_data;
161 /******************************************************************************
163 Authentication Routines
165 ******************************************************************************/
167 /* Encodes the authentication data for hashing and signing as the protocol
170 static unsigned char *
171 silc_auth_public_key_encode_data(SilcPublicKey public_key,
172 const unsigned char *random,
173 SilcUInt32 random_len, const void *id,
174 SilcIdType type, SilcUInt32 *ret_len)
177 unsigned char *pk, *id_data, *ret;
178 SilcUInt32 pk_len, id_len;
180 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
184 id_data = silc_id_id2str(id, type);
189 id_len = silc_id_get_len(id, type);
191 buf = silc_buffer_alloc_size(random_len + id_len + pk_len);
197 silc_buffer_format(buf,
198 SILC_STR_UI_XNSTRING(random, random_len),
199 SILC_STR_UI_XNSTRING(id_data, id_len),
200 SILC_STR_UI_XNSTRING(pk, pk_len),
203 ret = silc_memdup(buf->data, buf->len);
210 silc_buffer_free(buf);
217 /* Generates Authentication Payload with authentication data. This is used
218 to do public key based authentication. This generates the random data
219 and the actual authentication data. Returns NULL on error. */
221 SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
222 SilcPrivateKey private_key,
223 SilcRng rng, SilcHash hash,
224 const void *id, SilcIdType type)
226 unsigned char *random;
227 unsigned char auth_data[1024];
234 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
236 /* Get 256 bytes of random data */
238 random = silc_rng_get_rn_data(rng, 256);
240 random = silc_rng_global_get_rn_data(256);
244 /* Encode the auth data */
245 tmp = silc_auth_public_key_encode_data(public_key, random, 256, id, type,
250 /* Allocate PKCS object */
251 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
252 memset(tmp, 0, tmp_len);
256 silc_pkcs_public_key_set(pkcs, public_key);
257 silc_pkcs_private_key_set(pkcs, private_key);
259 /* Compute the hash and the signature. */
260 if (!silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
262 memset(random, 0, 256);
263 memset(tmp, 0, tmp_len);
266 silc_pkcs_free(pkcs);
270 /* Encode Authentication Payload */
271 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, random, 256,
272 auth_data, auth_len);
274 memset(tmp, 0, tmp_len);
275 memset(auth_data, 0, sizeof(auth_data));
276 memset(random, 0, 256);
279 silc_pkcs_free(pkcs);
284 /* Verifies the authentication data. Returns TRUE if authentication was
287 bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
288 SilcPublicKey public_key, SilcHash hash,
289 const void *id, SilcIdType type)
295 SILC_LOG_DEBUG(("Verifying authentication data"));
297 /* Encode auth data */
298 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
302 SILC_LOG_DEBUG(("Authentication failed"));
306 /* Allocate PKCS object */
307 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
308 memset(tmp, 0, tmp_len);
312 silc_pkcs_public_key_set(pkcs, public_key);
314 /* Verify the authentication data */
315 if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
316 payload->auth_len, tmp, tmp_len)) {
318 memset(tmp, 0, tmp_len);
320 silc_pkcs_free(pkcs);
321 SILC_LOG_DEBUG(("Authentication failed"));
325 memset(tmp, 0, tmp_len);
327 silc_pkcs_free(pkcs);
329 SILC_LOG_DEBUG(("Authentication successful"));
334 /* Same as above but the payload is not parsed yet. This will parse it. */
336 bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
337 SilcUInt32 payload_len,
338 SilcPublicKey public_key,
340 const void *id, SilcIdType type)
342 SilcAuthPayload auth_payload;
345 auth_payload = silc_auth_payload_parse(payload, payload_len);
347 SILC_LOG_DEBUG(("Authentication failed"));
351 ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
354 silc_auth_payload_free(auth_payload);
359 /* Verifies the authentication data directly from the Authentication
360 Payload. Supports all authentication methods. If the authentication
361 method is passphrase based then the `auth_data' and `auth_data_len'
362 are the passphrase and its length. If the method is public key
363 authentication then the `auth_data' is the SilcPublicKey and the
364 `auth_data_len' is ignored. */
366 bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
367 const void *auth_data, SilcUInt32 auth_data_len,
368 SilcHash hash, const void *id, SilcIdType type)
370 SILC_LOG_DEBUG(("Verifying authentication"));
372 if (!payload || auth_method != payload->auth_method)
375 switch (payload->auth_method) {
377 /* No authentication */
378 SILC_LOG_DEBUG(("No authentication required"));
381 case SILC_AUTH_PASSWORD:
382 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
383 arguments are not needed. */
386 if ((payload->auth_len == 0) || !auth_data ||
387 payload->auth_len != auth_data_len)
390 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
391 SILC_LOG_DEBUG(("Passphrase Authentication successful"));
396 case SILC_AUTH_PUBLIC_KEY:
397 /* Public key based authentication */
398 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
406 SILC_LOG_DEBUG(("Authentication failed"));
411 /* Same as above but parses the authentication payload before verify. */
413 bool silc_auth_verify_data(const unsigned char *payload,
414 SilcUInt32 payload_len,
415 SilcAuthMethod auth_method, const void *auth_data,
416 SilcUInt32 auth_data_len, SilcHash hash,
417 const void *id, SilcIdType type)
419 SilcAuthPayload auth_payload;
422 auth_payload = silc_auth_payload_parse(payload, payload_len);
423 if (!auth_payload || (auth_payload->auth_len == 0))
426 ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
429 silc_auth_payload_free(auth_payload);
434 /******************************************************************************
436 Key Agreement Payload
438 ******************************************************************************/
440 /* The Key Agreement protocol structure */
441 struct SilcKeyAgreementPayloadStruct {
442 SilcUInt16 hostname_len;
443 unsigned char *hostname;
447 /* Parses and returns an allocated Key Agreement payload. */
449 SilcKeyAgreementPayload
450 silc_key_agreement_payload_parse(const unsigned char *payload,
451 SilcUInt32 payload_len)
453 SilcBufferStruct buffer;
454 SilcKeyAgreementPayload newp;
457 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
459 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
460 newp = silc_calloc(1, sizeof(*newp));
464 /* Parse the payload */
465 ret = silc_buffer_unformat(&buffer,
466 SILC_STR_UI16_NSTRING_ALLOC(&newp->hostname,
467 &newp->hostname_len),
468 SILC_STR_UI_INT(&newp->port),
478 /* Encodes the Key Agreement protocol and returns the encoded buffer */
480 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
484 SilcUInt32 len = hostname ? strlen(hostname) : 0;
486 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
488 buffer = silc_buffer_alloc_size(2 + len + 4);
491 silc_buffer_format(buffer,
492 SILC_STR_UI_SHORT(len),
493 SILC_STR_UI_XNSTRING(hostname, len),
494 SILC_STR_UI_INT(port),
500 /* Frees the Key Agreement protocol */
502 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
505 silc_free(payload->hostname);
510 /* Returns the hostname in the payload */
512 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
514 return payload->hostname;
517 /* Returns the port in the payload */
519 SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
521 return payload->port;