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 silc_auth_payload_free(newp);
76 /* If password authentication, random data must not be set */
77 if (newp->auth_method == SILC_AUTH_PASSWORD && newp->random_len) {
78 silc_auth_payload_free(newp);
82 /* If public key authentication, random data must be at least 128 bytes */
83 if (newp->auth_method == SILC_AUTH_PUBLIC_KEY && newp->random_len < 128) {
84 silc_auth_payload_free(newp);
91 /* Encodes authentication payload into buffer and returns it */
93 SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
94 const unsigned char *random_data,
95 SilcUInt16 random_len,
96 const unsigned char *auth_data,
101 unsigned char *autf8 = NULL;
102 SilcUInt32 autf8_len;
104 SILC_LOG_DEBUG(("Encoding Authentication Payload"));
106 /* Passphrase MUST be UTF-8 encoded, encode if it is not */
107 if (method == SILC_AUTH_PASSWORD && !silc_utf8_valid(auth_data, auth_len)) {
108 autf8_len = silc_utf8_encoded_len(auth_data, auth_len, 0);
111 autf8 = silc_calloc(autf8_len, sizeof(*autf8));
112 auth_len = silc_utf8_encode(auth_data, auth_len, 0, autf8, autf8_len);
113 auth_data = (const unsigned char *)autf8;
116 len = 2 + 2 + 2 + random_len + 2 + auth_len;
117 buffer = silc_buffer_alloc_size(len);
123 silc_buffer_format(buffer,
124 SILC_STR_UI_SHORT(len),
125 SILC_STR_UI_SHORT(method),
126 SILC_STR_UI_SHORT(random_len),
127 SILC_STR_UI_XNSTRING(random_data, random_len),
128 SILC_STR_UI_SHORT(auth_len),
129 SILC_STR_UI_XNSTRING(auth_data, auth_len),
136 /* Frees authentication payload. */
138 void silc_auth_payload_free(SilcAuthPayload payload)
141 if (payload->random_data) {
142 memset(payload->random_data, 0, payload->random_len);
143 silc_free(payload->random_data);
145 if (payload->auth_data) {
146 memset(payload->auth_data, 0, payload->auth_len);
147 silc_free(payload->auth_data);
153 /* Get authentication method */
155 SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload)
157 return payload->auth_method;
160 /* Get the authentication data. If this is passphrase it is UTF-8 encoded. */
162 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
163 SilcUInt32 *auth_len)
166 *auth_len = payload->auth_len;
168 return payload->auth_data;
171 /******************************************************************************
173 Authentication Routines
175 ******************************************************************************/
177 /* Encodes the authentication data for hashing and signing as the protocol
180 static unsigned char *
181 silc_auth_public_key_encode_data(SilcPublicKey public_key,
182 const unsigned char *random,
183 SilcUInt32 random_len, const void *id,
184 SilcIdType type, SilcUInt32 *ret_len)
187 unsigned char *pk, *id_data, *ret;
188 SilcUInt32 pk_len, id_len;
190 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
194 id_data = silc_id_id2str(id, type);
199 id_len = silc_id_get_len(id, type);
201 buf = silc_buffer_alloc_size(random_len + id_len + pk_len);
207 silc_buffer_format(buf,
208 SILC_STR_UI_XNSTRING(random, random_len),
209 SILC_STR_UI_XNSTRING(id_data, id_len),
210 SILC_STR_UI_XNSTRING(pk, pk_len),
213 ret = silc_memdup(buf->data, buf->len);
220 silc_buffer_free(buf);
227 /* Generates Authentication Payload with authentication data. This is used
228 to do public key based authentication. This generates the random data
229 and the actual authentication data. Returns NULL on error. */
231 SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
232 SilcPrivateKey private_key,
233 SilcRng rng, SilcHash hash,
234 const void *id, SilcIdType type)
236 unsigned char *random;
237 unsigned char auth_data[1024];
244 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
246 /* Get 256 bytes of random data */
248 random = silc_rng_get_rn_data(rng, 256);
250 random = silc_rng_global_get_rn_data(256);
254 /* Encode the auth data */
255 tmp = silc_auth_public_key_encode_data(public_key, random, 256, id, type,
260 /* Allocate PKCS object */
261 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
262 memset(tmp, 0, tmp_len);
266 silc_pkcs_public_key_set(pkcs, public_key);
267 silc_pkcs_private_key_set(pkcs, private_key);
269 /* Compute the hash and the signature. */
270 if (!silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
272 memset(random, 0, 256);
273 memset(tmp, 0, tmp_len);
276 silc_pkcs_free(pkcs);
280 /* Encode Authentication Payload */
281 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, random, 256,
282 auth_data, auth_len);
284 memset(tmp, 0, tmp_len);
285 memset(auth_data, 0, sizeof(auth_data));
286 memset(random, 0, 256);
289 silc_pkcs_free(pkcs);
294 /* Verifies the authentication data. Returns TRUE if authentication was
297 bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
298 SilcPublicKey public_key, SilcHash hash,
299 const void *id, SilcIdType type)
305 SILC_LOG_DEBUG(("Verifying authentication data"));
307 /* Encode auth data */
308 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
312 SILC_LOG_DEBUG(("Authentication failed"));
316 /* Allocate PKCS object */
317 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
318 memset(tmp, 0, tmp_len);
322 silc_pkcs_public_key_set(pkcs, public_key);
324 /* Verify the authentication data */
325 if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
326 payload->auth_len, tmp, tmp_len)) {
328 memset(tmp, 0, tmp_len);
330 silc_pkcs_free(pkcs);
331 SILC_LOG_DEBUG(("Authentication failed"));
335 memset(tmp, 0, tmp_len);
337 silc_pkcs_free(pkcs);
339 SILC_LOG_DEBUG(("Authentication successful"));
344 /* Same as above but the payload is not parsed yet. This will parse it. */
346 bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
347 SilcUInt32 payload_len,
348 SilcPublicKey public_key,
350 const void *id, SilcIdType type)
352 SilcAuthPayload auth_payload;
355 auth_payload = silc_auth_payload_parse(payload, payload_len);
357 SILC_LOG_DEBUG(("Authentication failed"));
361 ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
364 silc_auth_payload_free(auth_payload);
369 /* Verifies the authentication data directly from the Authentication
370 Payload. Supports all authentication methods. If the authentication
371 method is passphrase based then the `auth_data' and `auth_data_len'
372 are the passphrase and its length. If the method is public key
373 authentication then the `auth_data' is the SilcPublicKey and the
374 `auth_data_len' is ignored. */
376 bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
377 const void *auth_data, SilcUInt32 auth_data_len,
378 SilcHash hash, const void *id, SilcIdType type)
380 SILC_LOG_DEBUG(("Verifying authentication"));
382 if (auth_method != payload->auth_method)
385 switch (payload->auth_method) {
387 /* No authentication */
388 SILC_LOG_DEBUG(("No authentication required"));
391 case SILC_AUTH_PASSWORD:
392 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
393 arguments are not needed. */
394 /* Carefully check that the auth_data field of the payload is not empty
395 (len=0), which seems to be a legal packet but would crash the
396 application. Maybe such packet should be dropped. -Johnny 2002/14/4 */
397 if ((payload->auth_len == 0) || !auth_data)
400 /* if lengths mismatch, avoid comparing unallocated memory locations */
401 if (payload->auth_len != auth_data_len)
403 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
404 SILC_LOG_DEBUG(("Passphrase Authentication successful"));
409 case SILC_AUTH_PUBLIC_KEY:
410 /* Public key based authentication */
411 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
419 SILC_LOG_DEBUG(("Authentication failed"));
424 /* Same as above but parses the authentication payload before verify. */
426 bool silc_auth_verify_data(const unsigned char *payload,
427 SilcUInt32 payload_len,
428 SilcAuthMethod auth_method, const void *auth_data,
429 SilcUInt32 auth_data_len, SilcHash hash,
430 const void *id, SilcIdType type)
432 SilcAuthPayload auth_payload;
435 auth_payload = silc_auth_payload_parse(payload, payload_len);
436 if (!auth_payload || (auth_payload->auth_len == 0))
439 ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
442 silc_auth_payload_free(auth_payload);
447 /******************************************************************************
449 Key Agreement Payload
451 ******************************************************************************/
453 /* The Key Agreement protocol structure */
454 struct SilcKeyAgreementPayloadStruct {
455 SilcUInt16 hostname_len;
456 unsigned char *hostname;
460 /* Parses and returns an allocated Key Agreement payload. */
462 SilcKeyAgreementPayload
463 silc_key_agreement_payload_parse(const unsigned char *payload,
464 SilcUInt32 payload_len)
466 SilcBufferStruct buffer;
467 SilcKeyAgreementPayload newp;
470 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
472 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
473 newp = silc_calloc(1, sizeof(*newp));
477 /* Parse the payload */
478 ret = silc_buffer_unformat(&buffer,
479 SILC_STR_UI16_NSTRING_ALLOC(&newp->hostname,
480 &newp->hostname_len),
481 SILC_STR_UI_INT(&newp->port),
491 /* Encodes the Key Agreement protocol and returns the encoded buffer */
493 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
497 SilcUInt32 len = hostname ? strlen(hostname) : 0;
499 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
501 buffer = silc_buffer_alloc_size(2 + len + 4);
504 silc_buffer_format(buffer,
505 SILC_STR_UI_SHORT(len),
506 SILC_STR_UI_XNSTRING(hostname, len),
507 SILC_STR_UI_INT(port),
513 /* Frees the Key Agreement protocol */
515 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
518 silc_free(payload->hostname);
523 /* Returns the hostname in the payload */
525 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
527 return payload->hostname;
530 /* Returns the port in the payload */
532 SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
534 return payload->port;