5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2005 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.
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 != silc_buffer_len(&buffer) ||
71 newp->random_len + newp->auth_len > silc_buffer_len(&buffer) - 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 public data from the auth payload. */
168 unsigned char *silc_auth_get_public_data(SilcAuthPayload payload,
169 SilcUInt32 *pubdata_len)
172 *pubdata_len = (SilcUInt32)payload->random_len;
174 return payload->random_data;
177 /* Get the authentication data. If this is passphrase it is UTF-8 encoded. */
179 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
180 SilcUInt32 *auth_len)
183 *auth_len = (SilcUInt32)payload->auth_len;
185 return payload->auth_data;
188 /******************************************************************************
190 Authentication Routines
192 ******************************************************************************/
194 /* Encodes the authentication data for hashing and signing as the protocol
197 static unsigned char *
198 silc_auth_public_key_encode_data(SilcPublicKey public_key,
199 const unsigned char *randomdata,
200 SilcUInt32 random_len, const void *id,
201 SilcIdType type, SilcUInt32 *ret_len)
204 unsigned char *pk, id_data[32], *ret;
205 SilcUInt32 pk_len, id_len;
207 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
211 if (!silc_id_id2str(id, type, id_data, sizeof(id_data), &id_len)) {
216 buf = silc_buffer_alloc_size(random_len + id_len + pk_len);
221 silc_buffer_format(buf,
222 SILC_STR_UI_XNSTRING(randomdata, random_len),
223 SILC_STR_UI_XNSTRING(id_data, id_len),
224 SILC_STR_UI_XNSTRING(pk, pk_len),
227 ret = silc_buffer_steal(buf, ret_len);
229 silc_buffer_free(buf);
235 /* Generates Authentication Payload with authentication data. This is used
236 to do public key based authentication. This generates the random data
237 and the actual authentication data. Returns NULL on error. */
239 SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
240 SilcPrivateKey private_key,
241 SilcRng rng, SilcHash hash,
242 const void *id, SilcIdType type)
244 unsigned char *randomdata;
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 buf = silc_auth_public_key_auth_generate_wpub(public_key, private_key,
256 randomdata, 256, hash,
259 memset(randomdata, 0, 256);
260 silc_free(randomdata);
265 /* Generates Authentication Payload with authentication data. This is used
266 to do public key based authentication. This generates the random data
267 and the actual authentication data. Returns NULL on error. */
270 silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
271 SilcPrivateKey private_key,
272 const unsigned char *pubdata,
273 SilcUInt32 pubdata_len,
275 const void *id, SilcIdType type)
277 unsigned char auth_data[2048 + 1];
284 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
286 /* Encode the auth data */
287 tmp = silc_auth_public_key_encode_data(public_key, pubdata, pubdata_len, id,
292 /* Allocate PKCS object */
293 if (!silc_pkcs_alloc(private_key->name, SILC_PKCS_SILC, &pkcs)) {
294 memset(tmp, 0, tmp_len);
298 silc_pkcs_public_key_set(pkcs, public_key);
299 silc_pkcs_private_key_set(pkcs, private_key);
301 /* Compute the hash and the signature. */
302 if (silc_pkcs_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 ||
303 !silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
305 memset(tmp, 0, tmp_len);
307 silc_pkcs_free(pkcs);
311 /* Encode Authentication Payload */
312 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, pubdata, pubdata_len,
313 auth_data, auth_len);
315 memset(tmp, 0, tmp_len);
316 memset(auth_data, 0, sizeof(auth_data));
318 silc_pkcs_free(pkcs);
323 /* Verifies the authentication data. Returns TRUE if authentication was
326 SilcBool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
327 SilcPublicKey public_key,
329 const void *id, SilcIdType type)
335 SILC_LOG_DEBUG(("Verifying authentication data"));
337 /* Encode auth data */
338 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
342 SILC_LOG_DEBUG(("Authentication failed"));
346 /* Allocate PKCS object */
347 if (!silc_pkcs_alloc(public_key->name, SILC_PKCS_SILC, &pkcs)) {
348 memset(tmp, 0, tmp_len);
352 silc_pkcs_public_key_set(pkcs, public_key);
354 /* Verify the authentication data */
355 if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
356 payload->auth_len, tmp, tmp_len)) {
358 memset(tmp, 0, tmp_len);
360 silc_pkcs_free(pkcs);
361 SILC_LOG_DEBUG(("Authentication failed"));
365 memset(tmp, 0, tmp_len);
367 silc_pkcs_free(pkcs);
369 SILC_LOG_DEBUG(("Authentication successful"));
374 /* Same as above but the payload is not parsed yet. This will parse it. */
376 SilcBool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
377 SilcUInt32 payload_len,
378 SilcPublicKey public_key,
380 const void *id, SilcIdType type)
382 SilcAuthPayload auth_payload;
385 auth_payload = silc_auth_payload_parse(payload, payload_len);
387 SILC_LOG_DEBUG(("Authentication failed"));
391 ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
394 silc_auth_payload_free(auth_payload);
399 /* Verifies the authentication data directly from the Authentication
400 Payload. Supports all authentication methods. If the authentication
401 method is passphrase based then the `auth_data' and `auth_data_len'
402 are the passphrase and its length. If the method is public key
403 authentication then the `auth_data' is the SilcPublicKey and the
404 `auth_data_len' is ignored. */
406 SilcBool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
407 const void *auth_data, SilcUInt32 auth_data_len,
408 SilcHash hash, const void *id, SilcIdType type)
410 SILC_LOG_DEBUG(("Verifying authentication"));
412 if (!payload || auth_method != payload->auth_method)
415 switch (payload->auth_method) {
417 /* No authentication */
418 SILC_LOG_DEBUG(("No authentication required"));
421 case SILC_AUTH_PASSWORD:
422 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
423 arguments are not needed. */
426 if ((payload->auth_len == 0) || !auth_data ||
427 payload->auth_len != auth_data_len)
430 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
431 SILC_LOG_DEBUG(("Passphrase Authentication successful"));
436 case SILC_AUTH_PUBLIC_KEY:
437 /* Public key based authentication */
438 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
446 SILC_LOG_DEBUG(("Authentication failed"));
451 /* Same as above but parses the authentication payload before verify. */
453 SilcBool silc_auth_verify_data(const unsigned char *payload,
454 SilcUInt32 payload_len,
455 SilcAuthMethod auth_method,
456 const void *auth_data,
457 SilcUInt32 auth_data_len, SilcHash hash,
458 const void *id, SilcIdType type)
460 SilcAuthPayload auth_payload;
463 auth_payload = silc_auth_payload_parse(payload, payload_len);
464 if (!auth_payload || (auth_payload->auth_len == 0))
467 ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
470 silc_auth_payload_free(auth_payload);
475 /******************************************************************************
477 Key Agreement Payload
479 ******************************************************************************/
481 /* The Key Agreement protocol structure */
482 struct SilcKeyAgreementPayloadStruct {
483 SilcUInt16 hostname_len;
484 unsigned char *hostname;
488 /* Parses and returns an allocated Key Agreement payload. */
490 SilcKeyAgreementPayload
491 silc_key_agreement_payload_parse(const unsigned char *payload,
492 SilcUInt32 payload_len)
494 SilcBufferStruct buffer;
495 SilcKeyAgreementPayload newp;
498 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
500 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
501 newp = silc_calloc(1, sizeof(*newp));
505 /* Parse the payload */
506 ret = silc_buffer_unformat(&buffer,
507 SILC_STR_UI16_NSTRING_ALLOC(&newp->hostname,
508 &newp->hostname_len),
509 SILC_STR_UI_INT(&newp->port),
511 if (ret == -1 || newp->hostname_len > silc_buffer_len(&buffer) - 6) {
519 /* Encodes the Key Agreement protocol and returns the encoded buffer */
521 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
525 SilcUInt32 len = hostname ? strlen(hostname) : 0;
527 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
529 buffer = silc_buffer_alloc_size(2 + len + 4);
532 silc_buffer_format(buffer,
533 SILC_STR_UI_SHORT(len),
534 SILC_STR_UI_XNSTRING(hostname, len),
535 SILC_STR_UI_INT(port),
541 /* Frees the Key Agreement protocol */
543 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
546 silc_free(payload->hostname);
551 /* Returns the hostname in the payload */
553 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
555 return payload->hostname;
558 /* Returns the port in the payload */
560 SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
562 return payload->port;