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[2048];
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_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 ||
278 !silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
280 memset(randomdata, 0, 256);
281 memset(tmp, 0, tmp_len);
283 silc_free(randomdata);
284 silc_pkcs_free(pkcs);
288 /* Encode Authentication Payload */
289 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, randomdata, 256,
290 auth_data, auth_len);
292 memset(tmp, 0, tmp_len);
293 memset(auth_data, 0, sizeof(auth_data));
294 memset(randomdata, 0, 256);
296 silc_free(randomdata);
297 silc_pkcs_free(pkcs);
302 /* Verifies the authentication data. Returns TRUE if authentication was
305 bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
306 SilcPublicKey public_key, SilcHash hash,
307 const void *id, SilcIdType type)
313 SILC_LOG_DEBUG(("Verifying authentication data"));
315 /* Encode auth data */
316 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
320 SILC_LOG_DEBUG(("Authentication failed"));
324 /* Allocate PKCS object */
325 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
326 memset(tmp, 0, tmp_len);
330 silc_pkcs_public_key_set(pkcs, public_key);
332 /* Verify the authentication data */
333 if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
334 payload->auth_len, tmp, tmp_len)) {
336 memset(tmp, 0, tmp_len);
338 silc_pkcs_free(pkcs);
339 SILC_LOG_DEBUG(("Authentication failed"));
343 memset(tmp, 0, tmp_len);
345 silc_pkcs_free(pkcs);
347 SILC_LOG_DEBUG(("Authentication successful"));
352 /* Same as above but the payload is not parsed yet. This will parse it. */
354 bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
355 SilcUInt32 payload_len,
356 SilcPublicKey public_key,
358 const void *id, SilcIdType type)
360 SilcAuthPayload auth_payload;
363 auth_payload = silc_auth_payload_parse(payload, payload_len);
365 SILC_LOG_DEBUG(("Authentication failed"));
369 ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
372 silc_auth_payload_free(auth_payload);
377 /* Verifies the authentication data directly from the Authentication
378 Payload. Supports all authentication methods. If the authentication
379 method is passphrase based then the `auth_data' and `auth_data_len'
380 are the passphrase and its length. If the method is public key
381 authentication then the `auth_data' is the SilcPublicKey and the
382 `auth_data_len' is ignored. */
384 bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
385 const void *auth_data, SilcUInt32 auth_data_len,
386 SilcHash hash, const void *id, SilcIdType type)
388 SILC_LOG_DEBUG(("Verifying authentication"));
390 if (!payload || auth_method != payload->auth_method)
393 switch (payload->auth_method) {
395 /* No authentication */
396 SILC_LOG_DEBUG(("No authentication required"));
399 case SILC_AUTH_PASSWORD:
400 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
401 arguments are not needed. */
404 if ((payload->auth_len == 0) || !auth_data ||
405 payload->auth_len != auth_data_len)
408 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
409 SILC_LOG_DEBUG(("Passphrase Authentication successful"));
414 case SILC_AUTH_PUBLIC_KEY:
415 /* Public key based authentication */
416 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
424 SILC_LOG_DEBUG(("Authentication failed"));
429 /* Same as above but parses the authentication payload before verify. */
431 bool silc_auth_verify_data(const unsigned char *payload,
432 SilcUInt32 payload_len,
433 SilcAuthMethod auth_method, const void *auth_data,
434 SilcUInt32 auth_data_len, SilcHash hash,
435 const void *id, SilcIdType type)
437 SilcAuthPayload auth_payload;
440 auth_payload = silc_auth_payload_parse(payload, payload_len);
441 if (!auth_payload || (auth_payload->auth_len == 0))
444 ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
447 silc_auth_payload_free(auth_payload);
452 /******************************************************************************
454 Key Agreement Payload
456 ******************************************************************************/
458 /* The Key Agreement protocol structure */
459 struct SilcKeyAgreementPayloadStruct {
460 SilcUInt16 hostname_len;
461 unsigned char *hostname;
465 /* Parses and returns an allocated Key Agreement payload. */
467 SilcKeyAgreementPayload
468 silc_key_agreement_payload_parse(const unsigned char *payload,
469 SilcUInt32 payload_len)
471 SilcBufferStruct buffer;
472 SilcKeyAgreementPayload newp;
475 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
477 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
478 newp = silc_calloc(1, sizeof(*newp));
482 /* Parse the payload */
483 ret = silc_buffer_unformat(&buffer,
484 SILC_STR_UI16_NSTRING_ALLOC(&newp->hostname,
485 &newp->hostname_len),
486 SILC_STR_UI_INT(&newp->port),
496 /* Encodes the Key Agreement protocol and returns the encoded buffer */
498 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
502 SilcUInt32 len = hostname ? strlen(hostname) : 0;
504 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
506 buffer = silc_buffer_alloc_size(2 + len + 4);
509 silc_buffer_format(buffer,
510 SILC_STR_UI_SHORT(len),
511 SILC_STR_UI_XNSTRING(hostname, len),
512 SILC_STR_UI_INT(port),
518 /* Frees the Key Agreement protocol */
520 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
523 silc_free(payload->hostname);
528 /* Returns the hostname in the payload */
530 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
532 return payload->hostname;
535 /* Returns the port in the payload */
537 SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
539 return payload->port;