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_memdup(buf->data, buf->len);
226 silc_buffer_clear(buf);
227 silc_buffer_free(buf);
234 /* Generates Authentication Payload with authentication data. This is used
235 to do public key based authentication. This generates the random data
236 and the actual authentication data. Returns NULL on error. */
238 SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
239 SilcPrivateKey private_key,
240 SilcRng rng, SilcHash hash,
241 const void *id, SilcIdType type)
243 unsigned char *randomdata;
244 unsigned char auth_data[2048 + 1];
251 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
253 /* Get 256 bytes of random data */
255 randomdata = silc_rng_get_rn_data(rng, 256);
257 randomdata = silc_rng_global_get_rn_data(256);
261 /* Encode the auth data */
262 tmp = silc_auth_public_key_encode_data(public_key, randomdata, 256, id,
267 /* Allocate PKCS object */
268 if (!silc_pkcs_alloc(private_key->name, &pkcs)) {
269 memset(tmp, 0, tmp_len);
273 silc_pkcs_public_key_set(pkcs, public_key);
274 silc_pkcs_private_key_set(pkcs, private_key);
276 /* Compute the hash and the signature. */
277 if (silc_pkcs_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 ||
278 !silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
280 memset(randomdata, 0, 256);
281 memset(tmp, 0, tmp_len);
283 silc_free(randomdata);
284 silc_pkcs_free(pkcs);
288 /* Encode Authentication Payload */
289 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, randomdata, 256,
290 auth_data, auth_len);
292 memset(tmp, 0, tmp_len);
293 memset(auth_data, 0, sizeof(auth_data));
294 memset(randomdata, 0, 256);
296 silc_free(randomdata);
297 silc_pkcs_free(pkcs);
302 /* Verifies the authentication data. Returns TRUE if authentication was
305 bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
306 SilcPublicKey public_key, SilcHash hash,
307 const void *id, SilcIdType type)
313 SILC_LOG_DEBUG(("Verifying authentication data"));
315 /* Encode auth data */
316 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
320 SILC_LOG_DEBUG(("Authentication failed"));
324 /* Allocate PKCS object */
325 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
326 memset(tmp, 0, tmp_len);
330 silc_pkcs_public_key_set(pkcs, public_key);
332 /* Verify the authentication data */
333 if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
334 payload->auth_len, tmp, tmp_len)) {
336 memset(tmp, 0, tmp_len);
338 silc_pkcs_free(pkcs);
339 SILC_LOG_DEBUG(("Authentication failed"));
343 memset(tmp, 0, tmp_len);
345 silc_pkcs_free(pkcs);
347 SILC_LOG_DEBUG(("Authentication successful"));
352 /* Same as above but the payload is not parsed yet. This will parse it. */
354 bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
355 SilcUInt32 payload_len,
356 SilcPublicKey public_key,
358 const void *id, SilcIdType type)
360 SilcAuthPayload auth_payload;
363 auth_payload = silc_auth_payload_parse(payload, payload_len);
365 SILC_LOG_DEBUG(("Authentication failed"));
369 ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
372 silc_auth_payload_free(auth_payload);
377 /* Verifies the authentication data directly from the Authentication
378 Payload. Supports all authentication methods. If the authentication
379 method is passphrase based then the `auth_data' and `auth_data_len'
380 are the passphrase and its length. If the method is public key
381 authentication then the `auth_data' is the SilcPublicKey and the
382 `auth_data_len' is ignored. */
384 bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
385 const void *auth_data, SilcUInt32 auth_data_len,
386 SilcHash hash, const void *id, SilcIdType type)
388 SILC_LOG_DEBUG(("Verifying authentication"));
390 if (!payload || auth_method != payload->auth_method)
393 switch (payload->auth_method) {
395 /* No authentication */
396 SILC_LOG_DEBUG(("No authentication required"));
399 case SILC_AUTH_PASSWORD:
400 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
401 arguments are not needed. */
404 if ((payload->auth_len == 0) || !auth_data ||
405 payload->auth_len != auth_data_len)
408 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
409 SILC_LOG_DEBUG(("Passphrase Authentication successful"));
414 case SILC_AUTH_PUBLIC_KEY:
415 /* Public key based authentication */
416 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
424 SILC_LOG_DEBUG(("Authentication failed"));
429 /* Same as above but parses the authentication payload before verify. */
431 bool silc_auth_verify_data(const unsigned char *payload,
432 SilcUInt32 payload_len,
433 SilcAuthMethod auth_method, const void *auth_data,
434 SilcUInt32 auth_data_len, SilcHash hash,
435 const void *id, SilcIdType type)
437 SilcAuthPayload auth_payload;
440 auth_payload = silc_auth_payload_parse(payload, payload_len);
441 if (!auth_payload || (auth_payload->auth_len == 0))
444 ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
447 silc_auth_payload_free(auth_payload);
452 /******************************************************************************
454 Key Agreement Payload
456 ******************************************************************************/
458 /* The Key Agreement protocol structure */
459 struct SilcKeyAgreementPayloadStruct {
460 SilcUInt16 hostname_len;
461 unsigned char *hostname;
465 /* Parses and returns an allocated Key Agreement payload. */
467 SilcKeyAgreementPayload
468 silc_key_agreement_payload_parse(const unsigned char *payload,
469 SilcUInt32 payload_len)
471 SilcBufferStruct buffer;
472 SilcKeyAgreementPayload newp;
475 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
477 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
478 newp = silc_calloc(1, sizeof(*newp));
482 /* Parse the payload */
483 ret = silc_buffer_unformat(&buffer,
484 SILC_STR_UI16_NSTRING_ALLOC(&newp->hostname,
485 &newp->hostname_len),
486 SILC_STR_UI_INT(&newp->port),
496 /* Encodes the Key Agreement protocol and returns the encoded buffer */
498 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
502 SilcUInt32 len = hostname ? strlen(hostname) : 0;
504 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
506 buffer = silc_buffer_alloc_size(2 + len + 4);
509 silc_buffer_format(buffer,
510 SILC_STR_UI_SHORT(len),
511 SILC_STR_UI_XNSTRING(hostname, len),
512 SILC_STR_UI_INT(port),
518 /* Frees the Key Agreement protocol */
520 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
523 silc_free(payload->hostname);
528 /* Returns the hostname in the payload */
530 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
532 return payload->hostname;
535 /* Returns the port in the payload */
537 SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
539 return payload->port;