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; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "silcincludes.h"
24 /******************************************************************************
26 Authentication Payload
28 ******************************************************************************/
30 /* Authentication Payload structure */
31 struct SilcAuthPayloadStruct {
33 SilcUInt16 auth_method;
34 SilcUInt16 random_len;
35 unsigned char *random_data;
37 unsigned char *auth_data;
40 /* Parses and returns Authentication Payload */
42 SilcAuthPayload silc_auth_payload_parse(const unsigned char *data,
45 SilcBufferStruct buffer;
49 SILC_LOG_DEBUG(("Parsing Authentication Payload"));
51 silc_buffer_set(&buffer, (unsigned char *)data, data_len);
52 newp = silc_calloc(1, sizeof(*newp));
56 /* Parse the payload */
57 ret = silc_buffer_unformat(&buffer,
58 SILC_STR_UI_SHORT(&newp->len),
59 SILC_STR_UI_SHORT(&newp->auth_method),
60 SILC_STR_UI16_NSTRING_ALLOC(&newp->random_data,
62 SILC_STR_UI16_NSTRING_ALLOC(&newp->auth_data,
70 if (newp->len != buffer.len ||
71 newp->random_len + newp->auth_len > buffer.len - 8) {
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,
107 unsigned char *autf8 = NULL;
108 SilcUInt32 autf8_len;
110 SILC_LOG_DEBUG(("Encoding Authentication Payload"));
112 /* Passphrase MUST be UTF-8 encoded, encode if it is not */
113 if (method == SILC_AUTH_PASSWORD && !silc_utf8_valid(auth_data, auth_len)) {
114 autf8_len = silc_utf8_encoded_len(auth_data, auth_len, 0);
117 autf8 = silc_calloc(autf8_len, sizeof(*autf8));
118 auth_len = silc_utf8_encode(auth_data, auth_len, 0, autf8, autf8_len);
119 auth_data = (const unsigned char *)autf8;
122 len = 2 + 2 + 2 + random_len + 2 + auth_len;
123 buffer = silc_buffer_alloc_size(len);
129 silc_buffer_format(buffer,
130 SILC_STR_UI_SHORT(len),
131 SILC_STR_UI_SHORT(method),
132 SILC_STR_UI_SHORT(random_len),
133 SILC_STR_UI_XNSTRING(random_data, random_len),
134 SILC_STR_UI_SHORT(auth_len),
135 SILC_STR_UI_XNSTRING(auth_data, auth_len),
142 /* Frees authentication payload. */
144 void silc_auth_payload_free(SilcAuthPayload payload)
147 if (payload->random_data) {
148 memset(payload->random_data, 0, payload->random_len);
149 silc_free(payload->random_data);
151 if (payload->auth_data) {
152 memset(payload->auth_data, 0, payload->auth_len);
153 silc_free(payload->auth_data);
159 /* Get authentication method */
161 SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload)
163 return payload->auth_method;
166 /* Get the authentication data. If this is passphrase it is UTF-8 encoded. */
168 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
169 SilcUInt32 *auth_len)
172 *auth_len = payload->auth_len;
174 return payload->auth_data;
177 /******************************************************************************
179 Authentication Routines
181 ******************************************************************************/
183 /* Encodes the authentication data for hashing and signing as the protocol
186 static unsigned char *
187 silc_auth_public_key_encode_data(SilcPublicKey public_key,
188 const unsigned char *randomdata,
189 SilcUInt32 random_len, const void *id,
190 SilcIdType type, SilcUInt32 *ret_len)
193 unsigned char *pk, *id_data, *ret;
194 SilcUInt32 pk_len, id_len;
196 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
200 id_data = silc_id_id2str(id, type);
205 id_len = silc_id_get_len(id, type);
207 buf = silc_buffer_alloc_size(random_len + id_len + pk_len);
213 silc_buffer_format(buf,
214 SILC_STR_UI_XNSTRING(randomdata, random_len),
215 SILC_STR_UI_XNSTRING(id_data, id_len),
216 SILC_STR_UI_XNSTRING(pk, pk_len),
219 ret = silc_buffer_steal(buf, ret_len);
221 silc_buffer_free(buf);
228 /* Generates Authentication Payload with authentication data. This is used
229 to do public key based authentication. This generates the random data
230 and the actual authentication data. Returns NULL on error. */
232 SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
233 SilcPrivateKey private_key,
234 SilcRng rng, SilcHash hash,
235 const void *id, SilcIdType type)
237 unsigned char *randomdata;
238 unsigned char auth_data[2048 + 1];
245 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
247 /* Get 256 bytes of random data */
249 randomdata = silc_rng_get_rn_data(rng, 256);
251 randomdata = silc_rng_global_get_rn_data(256);
255 /* Encode the auth data */
256 tmp = silc_auth_public_key_encode_data(public_key, randomdata, 256, id,
261 /* Allocate PKCS object */
262 if (!silc_pkcs_alloc(private_key->name, &pkcs)) {
263 memset(tmp, 0, tmp_len);
267 silc_pkcs_public_key_set(pkcs, public_key);
268 silc_pkcs_private_key_set(pkcs, private_key);
270 /* Compute the hash and the signature. */
271 if (silc_pkcs_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 ||
272 !silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
274 memset(randomdata, 0, 256);
275 memset(tmp, 0, tmp_len);
277 silc_free(randomdata);
278 silc_pkcs_free(pkcs);
282 /* Encode Authentication Payload */
283 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, randomdata, 256,
284 auth_data, auth_len);
286 memset(tmp, 0, tmp_len);
287 memset(auth_data, 0, sizeof(auth_data));
288 memset(randomdata, 0, 256);
290 silc_free(randomdata);
291 silc_pkcs_free(pkcs);
296 /* Verifies the authentication data. Returns TRUE if authentication was
299 bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
300 SilcPublicKey public_key, SilcHash hash,
301 const void *id, SilcIdType type)
307 SILC_LOG_DEBUG(("Verifying authentication data"));
309 /* Encode auth data */
310 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
314 SILC_LOG_DEBUG(("Authentication failed"));
318 /* Allocate PKCS object */
319 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
320 memset(tmp, 0, tmp_len);
324 silc_pkcs_public_key_set(pkcs, public_key);
326 /* Verify the authentication data */
327 if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
328 payload->auth_len, tmp, tmp_len)) {
330 memset(tmp, 0, tmp_len);
332 silc_pkcs_free(pkcs);
333 SILC_LOG_DEBUG(("Authentication failed"));
337 memset(tmp, 0, tmp_len);
339 silc_pkcs_free(pkcs);
341 SILC_LOG_DEBUG(("Authentication successful"));
346 /* Same as above but the payload is not parsed yet. This will parse it. */
348 bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
349 SilcUInt32 payload_len,
350 SilcPublicKey public_key,
352 const void *id, SilcIdType type)
354 SilcAuthPayload auth_payload;
357 auth_payload = silc_auth_payload_parse(payload, payload_len);
359 SILC_LOG_DEBUG(("Authentication failed"));
363 ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
366 silc_auth_payload_free(auth_payload);
371 /* Verifies the authentication data directly from the Authentication
372 Payload. Supports all authentication methods. If the authentication
373 method is passphrase based then the `auth_data' and `auth_data_len'
374 are the passphrase and its length. If the method is public key
375 authentication then the `auth_data' is the SilcPublicKey and the
376 `auth_data_len' is ignored. */
378 bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
379 const void *auth_data, SilcUInt32 auth_data_len,
380 SilcHash hash, const void *id, SilcIdType type)
382 SILC_LOG_DEBUG(("Verifying authentication"));
384 if (!payload || auth_method != payload->auth_method)
387 switch (payload->auth_method) {
389 /* No authentication */
390 SILC_LOG_DEBUG(("No authentication required"));
393 case SILC_AUTH_PASSWORD:
394 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
395 arguments are not needed. */
398 if ((payload->auth_len == 0) || !auth_data ||
399 payload->auth_len != auth_data_len)
402 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
403 SILC_LOG_DEBUG(("Passphrase Authentication successful"));
408 case SILC_AUTH_PUBLIC_KEY:
409 /* Public key based authentication */
410 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
418 SILC_LOG_DEBUG(("Authentication failed"));
423 /* Same as above but parses the authentication payload before verify. */
425 bool silc_auth_verify_data(const unsigned char *payload,
426 SilcUInt32 payload_len,
427 SilcAuthMethod auth_method, const void *auth_data,
428 SilcUInt32 auth_data_len, SilcHash hash,
429 const void *id, SilcIdType type)
431 SilcAuthPayload auth_payload;
434 auth_payload = silc_auth_payload_parse(payload, payload_len);
435 if (!auth_payload || (auth_payload->auth_len == 0))
438 ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
441 silc_auth_payload_free(auth_payload);
446 /******************************************************************************
448 Key Agreement Payload
450 ******************************************************************************/
452 /* The Key Agreement protocol structure */
453 struct SilcKeyAgreementPayloadStruct {
454 SilcUInt16 hostname_len;
455 unsigned char *hostname;
459 /* Parses and returns an allocated Key Agreement payload. */
461 SilcKeyAgreementPayload
462 silc_key_agreement_payload_parse(const unsigned char *payload,
463 SilcUInt32 payload_len)
465 SilcBufferStruct buffer;
466 SilcKeyAgreementPayload newp;
469 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
471 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
472 newp = silc_calloc(1, sizeof(*newp));
476 /* Parse the payload */
477 ret = silc_buffer_unformat(&buffer,
478 SILC_STR_UI16_NSTRING_ALLOC(&newp->hostname,
479 &newp->hostname_len),
480 SILC_STR_UI_INT(&newp->port),
490 /* Encodes the Key Agreement protocol and returns the encoded buffer */
492 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
496 SilcUInt32 len = hostname ? strlen(hostname) : 0;
498 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
500 buffer = silc_buffer_alloc_size(2 + len + 4);
503 silc_buffer_format(buffer,
504 SILC_STR_UI_SHORT(len),
505 SILC_STR_UI_XNSTRING(hostname, len),
506 SILC_STR_UI_INT(port),
512 /* Frees the Key Agreement protocol */
514 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
517 silc_free(payload->hostname);
522 /* Returns the hostname in the payload */
524 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
526 return payload->hostname;
529 /* Returns the port in the payload */
531 SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
533 return payload->port;