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);
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 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
395 SILC_LOG_DEBUG(("Authentication successful"));
400 case SILC_AUTH_PUBLIC_KEY:
401 /* Public key based authentication */
402 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
410 SILC_LOG_DEBUG(("Authentication failed"));
415 /* Same as above but parses the authentication payload before verify. */
417 bool silc_auth_verify_data(const unsigned char *payload,
418 SilcUInt32 payload_len,
419 SilcAuthMethod auth_method, const void *auth_data,
420 SilcUInt32 auth_data_len, SilcHash hash,
421 const void *id, SilcIdType type)
423 SilcAuthPayload auth_payload;
426 auth_payload = silc_auth_payload_parse(payload, payload_len);
430 ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
433 silc_auth_payload_free(auth_payload);
438 /******************************************************************************
440 Key Agreement Payload
442 ******************************************************************************/
444 /* The Key Agreement protocol structure */
445 struct SilcKeyAgreementPayloadStruct {
446 SilcUInt16 hostname_len;
447 unsigned char *hostname;
451 /* Parses and returns an allocated Key Agreement payload. */
453 SilcKeyAgreementPayload
454 silc_key_agreement_payload_parse(const unsigned char *payload,
455 SilcUInt32 payload_len)
457 SilcBufferStruct buffer;
458 SilcKeyAgreementPayload newp;
461 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
463 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
464 newp = silc_calloc(1, sizeof(*newp));
468 /* Parse the payload */
469 ret = silc_buffer_unformat(&buffer,
470 SILC_STR_UI16_NSTRING_ALLOC(&newp->hostname,
471 &newp->hostname_len),
472 SILC_STR_UI_INT(&newp->port),
482 /* Encodes the Key Agreement protocol and returns the encoded buffer */
484 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
488 SilcUInt32 len = hostname ? strlen(hostname) : 0;
490 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
492 buffer = silc_buffer_alloc_size(2 + len + 4);
495 silc_buffer_format(buffer,
496 SILC_STR_UI_SHORT(len),
497 SILC_STR_UI_XNSTRING(hostname, len),
498 SILC_STR_UI_INT(port),
504 /* Frees the Key Agreement protocol */
506 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
509 silc_free(payload->hostname);
514 /* Returns the hostname in the payload */
516 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
518 return payload->hostname;
521 /* Returns the port in the payload */
523 SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
525 return payload->port;