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 {
36 unsigned char *random_data;
38 unsigned char *auth_data;
41 /* Parses and returns Authentication Payload */
43 SilcAuthPayload silc_auth_payload_parse(unsigned char *data,
50 SILC_LOG_DEBUG(("Parsing Authentication Payload"));
52 buffer = silc_buffer_alloc(data_len);
53 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
54 silc_buffer_put(buffer, data, data_len);
56 new = silc_calloc(1, sizeof(*new));
58 /* Parse the payload */
59 ret = silc_buffer_unformat(buffer,
60 SILC_STR_UI_SHORT(&new->len),
61 SILC_STR_UI_SHORT(&new->auth_method),
62 SILC_STR_UI16_NSTRING_ALLOC(&new->random_data,
64 SILC_STR_UI16_NSTRING_ALLOC(&new->auth_data,
69 silc_buffer_free(buffer);
73 if (new->len != buffer->len) {
74 silc_auth_payload_free(new);
75 silc_buffer_free(buffer);
79 silc_buffer_free(buffer);
81 /* If password authentication, random data must not be set */
82 if (new->auth_method == SILC_AUTH_PASSWORD && new->random_len) {
83 silc_auth_payload_free(new);
90 /* Encodes authentication payload into buffer and returns it */
92 SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
93 unsigned char *random_data,
95 unsigned char *auth_data,
101 SILC_LOG_DEBUG(("Encoding Authentication Payload"));
103 len = 2 + 2 + 2 + random_len + 2 + auth_len;
104 buffer = silc_buffer_alloc(len);
105 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
106 silc_buffer_format(buffer,
107 SILC_STR_UI_SHORT(len),
108 SILC_STR_UI_SHORT(method),
109 SILC_STR_UI_SHORT(random_len),
110 SILC_STR_UI_XNSTRING(random_data, random_len),
111 SILC_STR_UI_SHORT(auth_len),
112 SILC_STR_UI_XNSTRING(auth_data, auth_len),
118 /* Frees authentication payload. */
120 void silc_auth_payload_free(SilcAuthPayload payload)
123 if (payload->random_data) {
124 memset(payload->random_data, 0, payload->random_len);
125 silc_free(payload->random_data);
127 if (payload->auth_data) {
128 memset(payload->auth_data, 0, payload->auth_len);
129 silc_free(payload->auth_data);
135 /* Get authentication method */
137 SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload)
139 return payload->auth_method;
142 /* Get the authentication data */
144 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
148 *auth_len = payload->auth_len;
150 return payload->auth_data;
153 /******************************************************************************
155 Authentication Routines
157 ******************************************************************************/
159 /* Encodes the authentication data for hashing and signing as the protocol
162 static unsigned char *
163 silc_auth_public_key_encode_data(SilcPublicKey public_key,
164 unsigned char *random,
165 uint32 random_len, void *id,
166 SilcIdType type, uint32 *ret_len)
169 unsigned char *pk, *id_data, *ret;
170 uint32 pk_len, id_len;
172 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
176 id_data = silc_id_id2str(id, type);
181 id_len = silc_id_get_len(id, type);
183 buf = silc_buffer_alloc(random_len + id_len + pk_len);
184 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
185 silc_buffer_format(buf,
186 SILC_STR_UI_XNSTRING(random, random_len),
187 SILC_STR_UI_XNSTRING(id_data, id_len),
188 SILC_STR_UI_XNSTRING(pk, pk_len),
191 ret = silc_calloc(buf->len + 1, sizeof(*ret));
192 memcpy(ret, buf->data, buf->len);
197 silc_buffer_free(buf);
204 /* Generates Authentication Payload with authentication data. This is used
205 to do public key based authentication. This generates the random data
206 and the actual authentication data. Returns NULL on error. */
208 SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
209 SilcPrivateKey private_key,
211 void *id, SilcIdType type)
213 unsigned char *random;
214 unsigned char auth_data[1024];
221 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
223 /* Get 256 bytes of random data */
224 random = silc_rng_global_get_rn_data(256);
228 /* Encode the auth data */
229 tmp = silc_auth_public_key_encode_data(public_key, random, 256, id, type,
234 /* Allocate PKCS object */
235 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
236 memset(tmp, 0, tmp_len);
240 silc_pkcs_public_key_set(pkcs, public_key);
241 silc_pkcs_private_key_set(pkcs, private_key);
243 /* Compute the hash and the signature. */
244 if (!silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
246 memset(random, 0, 256);
247 memset(tmp, 0, tmp_len);
250 silc_pkcs_free(pkcs);
254 /* Encode Authentication Payload */
255 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, random, 256,
256 auth_data, auth_len);
258 memset(tmp, 0, tmp_len);
259 memset(auth_data, 0, sizeof(auth_data));
260 memset(random, 0, 256);
263 silc_pkcs_free(pkcs);
268 /* Verifies the authentication data. Returns TRUE if authentication was
271 int silc_auth_public_key_auth_verify(SilcAuthPayload payload,
272 SilcPublicKey public_key, SilcHash hash,
273 void *id, SilcIdType type)
279 SILC_LOG_DEBUG(("Verifying authentication data"));
281 /* Encode auth data */
282 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
286 SILC_LOG_DEBUG(("Authentication failed"));
290 /* Allocate PKCS object */
291 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
292 memset(tmp, 0, tmp_len);
296 silc_pkcs_public_key_set(pkcs, public_key);
298 /* Verify the authentication data */
299 if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
300 payload->auth_len, tmp, tmp_len)) {
302 memset(tmp, 0, tmp_len);
304 silc_pkcs_free(pkcs);
305 SILC_LOG_DEBUG(("Authentication failed"));
309 memset(tmp, 0, tmp_len);
311 silc_pkcs_free(pkcs);
313 SILC_LOG_DEBUG(("Authentication successful"));
318 /* Same as above but the payload is not parsed yet. This will parse it. */
320 int silc_auth_public_key_auth_verify_data(SilcBuffer payload,
321 SilcPublicKey public_key,
323 void *id, SilcIdType type)
325 SilcAuthPayload auth_payload;
328 auth_payload = silc_auth_payload_parse(payload->data, payload->len);
330 SILC_LOG_DEBUG(("Authentication failed"));
334 ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
337 silc_auth_payload_free(auth_payload);
342 /* Verifies the authentication data directly from the Authentication
343 Payload. Supports all authentication methods. If the authentication
344 method is passphrase based then the `auth_data' and `auth_data_len'
345 are the passphrase and its length. If the method is public key
346 authentication then the `auth_data' is the SilcPublicKey and the
347 `auth_data_len' is ignored. */
349 int silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
350 void *auth_data, uint32 auth_data_len,
351 SilcHash hash, void *id, SilcIdType type)
353 SILC_LOG_DEBUG(("Verifying authentication"));
355 if (auth_method != payload->auth_method)
358 switch (payload->auth_method) {
360 /* No authentication */
361 SILC_LOG_DEBUG(("No authentication required"));
364 case SILC_AUTH_PASSWORD:
365 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
366 arguments are not needed. */
367 if (!memcmp(payload->auth_data, auth_data, payload->auth_len)) {
368 SILC_LOG_DEBUG(("Authentication successful"));
373 case SILC_AUTH_PUBLIC_KEY:
374 /* Public key based authentication */
375 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
383 SILC_LOG_DEBUG(("Authentication failed"));
388 /* Same as above but parses the authentication payload before verify. */
390 int silc_auth_verify_data(unsigned char *payload, uint32 payload_len,
391 SilcAuthMethod auth_method, void *auth_data,
392 uint32 auth_data_len, SilcHash hash,
393 void *id, SilcIdType type)
395 SilcAuthPayload auth_payload;
398 auth_payload = silc_auth_payload_parse(payload, payload_len);
402 ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
405 silc_auth_payload_free(auth_payload);
410 /******************************************************************************
412 Key Agreement Payload
414 ******************************************************************************/
416 /* The Key Agreement protocol structure */
417 struct SilcKeyAgreementPayloadStruct {
419 unsigned char *hostname;
423 /* Parses and returns an allocated Key Agreement payload. */
425 SilcKeyAgreementPayload silc_key_agreement_payload_parse(SilcBuffer buffer)
427 SilcKeyAgreementPayload new;
430 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
432 new = silc_calloc(1, sizeof(*new));
434 /* Parse the payload */
435 ret = silc_buffer_unformat(buffer,
436 SILC_STR_UI16_NSTRING_ALLOC(&new->hostname,
438 SILC_STR_UI_INT(&new->port),
448 /* Encodes the Key Agreement protocol and returns the encoded buffer */
450 SilcBuffer silc_key_agreement_payload_encode(char *hostname,
454 uint32 len = hostname ? strlen(hostname) : 0;
456 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
458 buffer = silc_buffer_alloc(2 + len + 4);
459 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
460 silc_buffer_format(buffer,
461 SILC_STR_UI_SHORT(len),
462 SILC_STR_UI_XNSTRING(hostname, len),
463 SILC_STR_UI_INT(port),
469 /* Frees the Key Agreement protocol */
471 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
474 silc_free(payload->hostname);
479 /* Returns the hostname in the payload */
481 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
483 return payload->hostname;
486 /* Returns the port in the payload */
488 uint32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
490 return payload->port;