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];
283 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
285 /* Encode the auth data */
286 tmp = silc_auth_public_key_encode_data(public_key, pubdata, pubdata_len, id,
291 /* Compute the hash and the signature. */
292 if (!silc_pkcs_sign(private_key, tmp, tmp_len, auth_data,
293 sizeof(auth_data) - 1, &auth_len, hash)) {
294 memset(tmp, 0, tmp_len);
299 /* Encode Authentication Payload */
300 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, pubdata, pubdata_len,
301 auth_data, auth_len);
303 memset(tmp, 0, tmp_len);
304 memset(auth_data, 0, sizeof(auth_data));
310 /* Verifies the authentication data. Returns TRUE if authentication was
313 SilcBool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
314 SilcPublicKey public_key,
316 const void *id, SilcIdType type)
321 SILC_LOG_DEBUG(("Verifying authentication data"));
323 /* Encode auth data */
324 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
328 SILC_LOG_DEBUG(("Authentication failed"));
332 /* Verify the authentication data */
333 if (!silc_pkcs_verify(public_key, payload->auth_data,
334 payload->auth_len, tmp, tmp_len, hash)) {
336 memset(tmp, 0, tmp_len);
338 SILC_LOG_DEBUG(("Authentication failed"));
342 memset(tmp, 0, tmp_len);
345 SILC_LOG_DEBUG(("Authentication successful"));
350 /* Same as above but the payload is not parsed yet. This will parse it. */
352 SilcBool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
353 SilcUInt32 payload_len,
354 SilcPublicKey public_key,
356 const void *id, SilcIdType type)
358 SilcAuthPayload auth_payload;
361 auth_payload = silc_auth_payload_parse(payload, payload_len);
363 SILC_LOG_DEBUG(("Authentication failed"));
367 ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
370 silc_auth_payload_free(auth_payload);
375 /* Verifies the authentication data directly from the Authentication
376 Payload. Supports all authentication methods. If the authentication
377 method is passphrase based then the `auth_data' and `auth_data_len'
378 are the passphrase and its length. If the method is public key
379 authentication then the `auth_data' is the SilcPublicKey and the
380 `auth_data_len' is ignored. */
382 SilcBool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
383 const void *auth_data, SilcUInt32 auth_data_len,
384 SilcHash hash, const void *id, SilcIdType type)
386 SILC_LOG_DEBUG(("Verifying authentication"));
388 if (!payload || auth_method != payload->auth_method)
391 switch (payload->auth_method) {
393 /* No authentication */
394 SILC_LOG_DEBUG(("No authentication required"));
397 case SILC_AUTH_PASSWORD:
398 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
399 arguments are not needed. */
402 if ((payload->auth_len == 0) || !auth_data ||
403 payload->auth_len != auth_data_len)
406 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
407 SILC_LOG_DEBUG(("Passphrase Authentication successful"));
412 case SILC_AUTH_PUBLIC_KEY:
413 /* Public key based authentication */
414 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
422 SILC_LOG_DEBUG(("Authentication failed"));
427 /* Same as above but parses the authentication payload before verify. */
429 SilcBool silc_auth_verify_data(const unsigned char *payload,
430 SilcUInt32 payload_len,
431 SilcAuthMethod auth_method,
432 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),
487 if (ret == -1 || newp->hostname_len > silc_buffer_len(&buffer) - 6) {
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;