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 newp->random_len + newp->auth_len > buffer.len - 8) {
73 silc_auth_payload_free(newp);
77 /* Authentication data must be provided */
78 if (newp->auth_len < 1) {
79 silc_auth_payload_free(newp);
83 /* If password authentication, random data must not be set */
84 if (newp->auth_method == SILC_AUTH_PASSWORD && newp->random_len) {
85 silc_auth_payload_free(newp);
89 /* If public key authentication, random data must be at least 128 bytes */
90 if (newp->auth_method == SILC_AUTH_PUBLIC_KEY && newp->random_len < 128) {
91 silc_auth_payload_free(newp);
98 /* Encodes authentication payload into buffer and returns it */
100 SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
101 const unsigned char *random_data,
102 SilcUInt16 random_len,
103 const unsigned char *auth_data,
108 unsigned char *autf8 = NULL;
109 SilcUInt32 autf8_len;
111 SILC_LOG_DEBUG(("Encoding Authentication Payload"));
113 /* Passphrase MUST be UTF-8 encoded, encode if it is not */
114 if (method == SILC_AUTH_PASSWORD && !silc_utf8_valid(auth_data, auth_len)) {
115 autf8_len = silc_utf8_encoded_len(auth_data, auth_len, 0);
118 autf8 = silc_calloc(autf8_len, sizeof(*autf8));
119 auth_len = silc_utf8_encode(auth_data, auth_len, 0, autf8, autf8_len);
120 auth_data = (const unsigned char *)autf8;
123 len = 2 + 2 + 2 + random_len + 2 + auth_len;
124 buffer = silc_buffer_alloc_size(len);
130 silc_buffer_format(buffer,
131 SILC_STR_UI_SHORT(len),
132 SILC_STR_UI_SHORT(method),
133 SILC_STR_UI_SHORT(random_len),
134 SILC_STR_UI_XNSTRING(random_data, random_len),
135 SILC_STR_UI_SHORT(auth_len),
136 SILC_STR_UI_XNSTRING(auth_data, auth_len),
143 /* Frees authentication payload. */
145 void silc_auth_payload_free(SilcAuthPayload payload)
148 if (payload->random_data) {
149 memset(payload->random_data, 0, payload->random_len);
150 silc_free(payload->random_data);
152 if (payload->auth_data) {
153 memset(payload->auth_data, 0, payload->auth_len);
154 silc_free(payload->auth_data);
160 /* Get authentication method */
162 SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload)
164 return payload->auth_method;
167 /* Get the authentication data. If this is passphrase it is UTF-8 encoded. */
169 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
170 SilcUInt32 *auth_len)
173 *auth_len = payload->auth_len;
175 return payload->auth_data;
178 /******************************************************************************
180 Authentication Routines
182 ******************************************************************************/
184 /* Encodes the authentication data for hashing and signing as the protocol
187 static unsigned char *
188 silc_auth_public_key_encode_data(SilcPublicKey public_key,
189 const unsigned char *randomdata,
190 SilcUInt32 random_len, const void *id,
191 SilcIdType type, SilcUInt32 *ret_len)
194 unsigned char *pk, *id_data, *ret;
195 SilcUInt32 pk_len, id_len;
197 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
201 id_data = silc_id_id2str(id, type);
206 id_len = silc_id_get_len(id, type);
208 buf = silc_buffer_alloc_size(random_len + id_len + pk_len);
214 silc_buffer_format(buf,
215 SILC_STR_UI_XNSTRING(randomdata, random_len),
216 SILC_STR_UI_XNSTRING(id_data, id_len),
217 SILC_STR_UI_XNSTRING(pk, pk_len),
220 ret = silc_memdup(buf->data, buf->len);
227 silc_buffer_free(buf);
234 /* Generates Authentication Payload with authentication data. This is used
235 to do public key based authentication. This generates the random data
236 and the actual authentication data. Returns NULL on error. */
238 SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
239 SilcPrivateKey private_key,
240 SilcRng rng, SilcHash hash,
241 const void *id, SilcIdType type)
243 unsigned char *randomdata;
244 unsigned char auth_data[1024];
251 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
253 /* Get 256 bytes of random data */
255 randomdata = silc_rng_get_rn_data(rng, 256);
257 randomdata = silc_rng_global_get_rn_data(256);
261 /* Encode the auth data */
262 tmp = silc_auth_public_key_encode_data(public_key, randomdata, 256, id,
267 /* Allocate PKCS object */
268 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
269 memset(tmp, 0, tmp_len);
273 silc_pkcs_public_key_set(pkcs, public_key);
274 silc_pkcs_private_key_set(pkcs, private_key);
276 /* Compute the hash and the signature. */
277 if (!silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
279 memset(randomdata, 0, 256);
280 memset(tmp, 0, tmp_len);
282 silc_free(randomdata);
283 silc_pkcs_free(pkcs);
287 /* Encode Authentication Payload */
288 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, randomdata, 256,
289 auth_data, auth_len);
291 memset(tmp, 0, tmp_len);
292 memset(auth_data, 0, sizeof(auth_data));
293 memset(randomdata, 0, 256);
295 silc_free(randomdata);
296 silc_pkcs_free(pkcs);
301 /* Verifies the authentication data. Returns TRUE if authentication was
304 bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
305 SilcPublicKey public_key, SilcHash hash,
306 const void *id, SilcIdType type)
312 SILC_LOG_DEBUG(("Verifying authentication data"));
314 /* Encode auth data */
315 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
319 SILC_LOG_DEBUG(("Authentication failed"));
323 /* Allocate PKCS object */
324 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
325 memset(tmp, 0, tmp_len);
329 silc_pkcs_public_key_set(pkcs, public_key);
331 /* Verify the authentication data */
332 if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
333 payload->auth_len, tmp, tmp_len)) {
335 memset(tmp, 0, tmp_len);
337 silc_pkcs_free(pkcs);
338 SILC_LOG_DEBUG(("Authentication failed"));
342 memset(tmp, 0, tmp_len);
344 silc_pkcs_free(pkcs);
346 SILC_LOG_DEBUG(("Authentication successful"));
351 /* Same as above but the payload is not parsed yet. This will parse it. */
353 bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
354 SilcUInt32 payload_len,
355 SilcPublicKey public_key,
357 const void *id, SilcIdType type)
359 SilcAuthPayload auth_payload;
362 auth_payload = silc_auth_payload_parse(payload, payload_len);
364 SILC_LOG_DEBUG(("Authentication failed"));
368 ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
371 silc_auth_payload_free(auth_payload);
376 /* Verifies the authentication data directly from the Authentication
377 Payload. Supports all authentication methods. If the authentication
378 method is passphrase based then the `auth_data' and `auth_data_len'
379 are the passphrase and its length. If the method is public key
380 authentication then the `auth_data' is the SilcPublicKey and the
381 `auth_data_len' is ignored. */
383 bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
384 const void *auth_data, SilcUInt32 auth_data_len,
385 SilcHash hash, const void *id, SilcIdType type)
387 SILC_LOG_DEBUG(("Verifying authentication"));
389 if (!payload || auth_method != payload->auth_method)
392 switch (payload->auth_method) {
394 /* No authentication */
395 SILC_LOG_DEBUG(("No authentication required"));
398 case SILC_AUTH_PASSWORD:
399 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
400 arguments are not needed. */
403 if ((payload->auth_len == 0) || !auth_data ||
404 payload->auth_len != auth_data_len)
407 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
408 SILC_LOG_DEBUG(("Passphrase Authentication successful"));
413 case SILC_AUTH_PUBLIC_KEY:
414 /* Public key based authentication */
415 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
423 SILC_LOG_DEBUG(("Authentication failed"));
428 /* Same as above but parses the authentication payload before verify. */
430 bool silc_auth_verify_data(const unsigned char *payload,
431 SilcUInt32 payload_len,
432 SilcAuthMethod auth_method, const void *auth_data,
433 SilcUInt32 auth_data_len, SilcHash hash,
434 const void *id, SilcIdType type)
436 SilcAuthPayload auth_payload;
439 auth_payload = silc_auth_payload_parse(payload, payload_len);
440 if (!auth_payload || (auth_payload->auth_len == 0))
443 ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
446 silc_auth_payload_free(auth_payload);
451 /******************************************************************************
453 Key Agreement Payload
455 ******************************************************************************/
457 /* The Key Agreement protocol structure */
458 struct SilcKeyAgreementPayloadStruct {
459 SilcUInt16 hostname_len;
460 unsigned char *hostname;
464 /* Parses and returns an allocated Key Agreement payload. */
466 SilcKeyAgreementPayload
467 silc_key_agreement_payload_parse(const unsigned char *payload,
468 SilcUInt32 payload_len)
470 SilcBufferStruct buffer;
471 SilcKeyAgreementPayload newp;
474 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
476 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
477 newp = silc_calloc(1, sizeof(*newp));
481 /* Parse the payload */
482 ret = silc_buffer_unformat(&buffer,
483 SILC_STR_UI16_NSTRING_ALLOC(&newp->hostname,
484 &newp->hostname_len),
485 SILC_STR_UI_INT(&newp->port),
495 /* Encodes the Key Agreement protocol and returns the encoded buffer */
497 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
501 SilcUInt32 len = hostname ? strlen(hostname) : 0;
503 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
505 buffer = silc_buffer_alloc_size(2 + len + 4);
508 silc_buffer_format(buffer,
509 SILC_STR_UI_SHORT(len),
510 SILC_STR_UI_XNSTRING(hostname, len),
511 SILC_STR_UI_INT(port),
517 /* Frees the Key Agreement protocol */
519 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
522 silc_free(payload->hostname);
527 /* Returns the hostname in the payload */
529 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
531 return payload->hostname;
534 /* Returns the port in the payload */
536 SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
538 return payload->port;