5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2001 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);
85 /* Encodes authentication payload into buffer and returns it */
87 SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
88 const unsigned char *random_data,
89 SilcUInt16 random_len,
90 const unsigned char *auth_data,
95 unsigned char *autf8 = NULL;
98 SILC_LOG_DEBUG(("Encoding Authentication Payload"));
100 /* Passphrase MUST be UTF-8 encoded, encode if it is not */
101 if (method == SILC_AUTH_PASSWORD && !silc_utf8_valid(auth_data, auth_len)) {
102 autf8_len = silc_utf8_encoded_len(auth_data, auth_len, 0);
105 autf8 = silc_calloc(autf8_len, sizeof(*autf8));
106 auth_len = silc_utf8_encode(auth_data, auth_len, 0, autf8, autf8_len);
107 auth_data = (const unsigned char *)autf8;
110 len = 2 + 2 + 2 + random_len + 2 + auth_len;
111 buffer = silc_buffer_alloc_size(len);
117 silc_buffer_format(buffer,
118 SILC_STR_UI_SHORT(len),
119 SILC_STR_UI_SHORT(method),
120 SILC_STR_UI_SHORT(random_len),
121 SILC_STR_UI_XNSTRING(random_data, random_len),
122 SILC_STR_UI_SHORT(auth_len),
123 SILC_STR_UI_XNSTRING(auth_data, auth_len),
130 /* Frees authentication payload. */
132 void silc_auth_payload_free(SilcAuthPayload payload)
135 if (payload->random_data) {
136 memset(payload->random_data, 0, payload->random_len);
137 silc_free(payload->random_data);
139 if (payload->auth_data) {
140 memset(payload->auth_data, 0, payload->auth_len);
141 silc_free(payload->auth_data);
147 /* Get authentication method */
149 SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload)
151 return payload->auth_method;
154 /* Get the authentication data. If this is passphrase it is UTF-8 encoded. */
156 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
157 SilcUInt32 *auth_len)
160 *auth_len = payload->auth_len;
162 return payload->auth_data;
165 /******************************************************************************
167 Authentication Routines
169 ******************************************************************************/
171 /* Encodes the authentication data for hashing and signing as the protocol
174 static unsigned char *
175 silc_auth_public_key_encode_data(SilcPublicKey public_key,
176 const unsigned char *random,
177 SilcUInt32 random_len, const void *id,
178 SilcIdType type, SilcUInt32 *ret_len)
181 unsigned char *pk, *id_data, *ret;
182 SilcUInt32 pk_len, id_len;
184 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
188 id_data = silc_id_id2str(id, type);
193 id_len = silc_id_get_len(id, type);
195 buf = silc_buffer_alloc_size(random_len + id_len + pk_len);
201 silc_buffer_format(buf,
202 SILC_STR_UI_XNSTRING(random, random_len),
203 SILC_STR_UI_XNSTRING(id_data, id_len),
204 SILC_STR_UI_XNSTRING(pk, pk_len),
207 ret = silc_memdup(buf->data, buf->len);
214 silc_buffer_free(buf);
221 /* Generates Authentication Payload with authentication data. This is used
222 to do public key based authentication. This generates the random data
223 and the actual authentication data. Returns NULL on error. */
225 SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
226 SilcPrivateKey private_key,
227 SilcRng rng, SilcHash hash,
228 const void *id, SilcIdType type)
230 unsigned char *random;
231 unsigned char auth_data[1024];
238 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
240 /* Get 256 bytes of random data */
242 random = silc_rng_get_rn_data(rng, 256);
244 random = silc_rng_global_get_rn_data(256);
248 /* Encode the auth data */
249 tmp = silc_auth_public_key_encode_data(public_key, random, 256, id, type,
254 /* Allocate PKCS object */
255 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
256 memset(tmp, 0, tmp_len);
260 silc_pkcs_public_key_set(pkcs, public_key);
261 silc_pkcs_private_key_set(pkcs, private_key);
263 /* Compute the hash and the signature. */
264 if (!silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
266 memset(random, 0, 256);
267 memset(tmp, 0, tmp_len);
270 silc_pkcs_free(pkcs);
274 /* Encode Authentication Payload */
275 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, random, 256,
276 auth_data, auth_len);
278 memset(tmp, 0, tmp_len);
279 memset(auth_data, 0, sizeof(auth_data));
280 memset(random, 0, 256);
283 silc_pkcs_free(pkcs);
288 /* Verifies the authentication data. Returns TRUE if authentication was
291 bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
292 SilcPublicKey public_key, SilcHash hash,
293 const void *id, SilcIdType type)
299 SILC_LOG_DEBUG(("Verifying authentication data"));
301 /* Encode auth data */
302 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
306 SILC_LOG_DEBUG(("Authentication failed"));
310 /* Allocate PKCS object */
311 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
312 memset(tmp, 0, tmp_len);
316 silc_pkcs_public_key_set(pkcs, public_key);
318 /* Verify the authentication data */
319 if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
320 payload->auth_len, tmp, tmp_len)) {
322 memset(tmp, 0, tmp_len);
324 silc_pkcs_free(pkcs);
325 SILC_LOG_DEBUG(("Authentication failed"));
329 memset(tmp, 0, tmp_len);
331 silc_pkcs_free(pkcs);
333 SILC_LOG_DEBUG(("Authentication successful"));
338 /* Same as above but the payload is not parsed yet. This will parse it. */
340 bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
341 SilcUInt32 payload_len,
342 SilcPublicKey public_key,
344 const void *id, SilcIdType type)
346 SilcAuthPayload auth_payload;
349 auth_payload = silc_auth_payload_parse(payload, payload_len);
351 SILC_LOG_DEBUG(("Authentication failed"));
355 ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
358 silc_auth_payload_free(auth_payload);
363 /* Verifies the authentication data directly from the Authentication
364 Payload. Supports all authentication methods. If the authentication
365 method is passphrase based then the `auth_data' and `auth_data_len'
366 are the passphrase and its length. If the method is public key
367 authentication then the `auth_data' is the SilcPublicKey and the
368 `auth_data_len' is ignored. */
370 bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
371 const void *auth_data, SilcUInt32 auth_data_len,
372 SilcHash hash, const void *id, SilcIdType type)
374 SILC_LOG_DEBUG(("Verifying authentication"));
376 if (auth_method != payload->auth_method)
379 switch (payload->auth_method) {
381 /* No authentication */
382 SILC_LOG_DEBUG(("No authentication required"));
385 case SILC_AUTH_PASSWORD:
386 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
387 arguments are not needed. */
388 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
389 SILC_LOG_DEBUG(("Authentication successful"));
394 case SILC_AUTH_PUBLIC_KEY:
395 /* Public key based authentication */
396 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
404 SILC_LOG_DEBUG(("Authentication failed"));
409 /* Same as above but parses the authentication payload before verify. */
411 bool silc_auth_verify_data(const unsigned char *payload,
412 SilcUInt32 payload_len,
413 SilcAuthMethod auth_method, const void *auth_data,
414 SilcUInt32 auth_data_len, SilcHash hash,
415 const void *id, SilcIdType type)
417 SilcAuthPayload auth_payload;
420 auth_payload = silc_auth_payload_parse(payload, payload_len);
424 ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
427 silc_auth_payload_free(auth_payload);
432 /******************************************************************************
434 Key Agreement Payload
436 ******************************************************************************/
438 /* The Key Agreement protocol structure */
439 struct SilcKeyAgreementPayloadStruct {
440 SilcUInt16 hostname_len;
441 unsigned char *hostname;
445 /* Parses and returns an allocated Key Agreement payload. */
447 SilcKeyAgreementPayload
448 silc_key_agreement_payload_parse(const unsigned char *payload,
449 SilcUInt32 payload_len)
451 SilcBufferStruct buffer;
452 SilcKeyAgreementPayload newp;
455 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
457 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
458 newp = silc_calloc(1, sizeof(*newp));
462 /* Parse the payload */
463 ret = silc_buffer_unformat(&buffer,
464 SILC_STR_UI16_NSTRING_ALLOC(&newp->hostname,
465 &newp->hostname_len),
466 SILC_STR_UI_INT(&newp->port),
476 /* Encodes the Key Agreement protocol and returns the encoded buffer */
478 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
482 SilcUInt32 len = hostname ? strlen(hostname) : 0;
484 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
486 buffer = silc_buffer_alloc_size(2 + len + 4);
489 silc_buffer_format(buffer,
490 SILC_STR_UI_SHORT(len),
491 SILC_STR_UI_XNSTRING(hostname, len),
492 SILC_STR_UI_INT(port),
498 /* Frees the Key Agreement protocol */
500 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
503 silc_free(payload->hostname);
508 /* Returns the hostname in the payload */
510 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
512 return payload->hostname;
515 /* Returns the port in the payload */
517 SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
519 return payload->port;