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(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 new = silc_calloc(1, sizeof(*new));
55 /* Parse the payload */
56 ret = silc_buffer_unformat(&buffer,
57 SILC_STR_UI_SHORT(&new->len),
58 SILC_STR_UI_SHORT(&new->auth_method),
59 SILC_STR_UI16_NSTRING_ALLOC(&new->random_data,
61 SILC_STR_UI16_NSTRING_ALLOC(&new->auth_data,
69 if (new->len != buffer.len) {
70 silc_auth_payload_free(new);
74 /* If password authentication, random data must not be set */
75 if (new->auth_method == SILC_AUTH_PASSWORD && new->random_len) {
76 silc_auth_payload_free(new);
83 /* Encodes authentication payload into buffer and returns it */
85 SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
86 const unsigned char *random_data,
88 const unsigned char *auth_data,
94 SILC_LOG_DEBUG(("Encoding Authentication Payload"));
96 len = 2 + 2 + 2 + random_len + 2 + auth_len;
97 buffer = silc_buffer_alloc(len);
98 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
99 silc_buffer_format(buffer,
100 SILC_STR_UI_SHORT(len),
101 SILC_STR_UI_SHORT(method),
102 SILC_STR_UI_SHORT(random_len),
103 SILC_STR_UI_XNSTRING(random_data, random_len),
104 SILC_STR_UI_SHORT(auth_len),
105 SILC_STR_UI_XNSTRING(auth_data, auth_len),
111 /* Frees authentication payload. */
113 void silc_auth_payload_free(SilcAuthPayload payload)
116 if (payload->random_data) {
117 memset(payload->random_data, 0, payload->random_len);
118 silc_free(payload->random_data);
120 if (payload->auth_data) {
121 memset(payload->auth_data, 0, payload->auth_len);
122 silc_free(payload->auth_data);
128 /* Get authentication method */
130 SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload)
132 return payload->auth_method;
135 /* Get the authentication data */
137 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
141 *auth_len = payload->auth_len;
143 return payload->auth_data;
146 /******************************************************************************
148 Authentication Routines
150 ******************************************************************************/
152 /* Encodes the authentication data for hashing and signing as the protocol
155 static unsigned char *
156 silc_auth_public_key_encode_data(SilcPublicKey public_key,
157 const unsigned char *random,
158 uint32 random_len, const void *id,
159 SilcIdType type, uint32 *ret_len)
162 unsigned char *pk, *id_data, *ret;
163 uint32 pk_len, id_len;
165 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
169 id_data = silc_id_id2str(id, type);
174 id_len = silc_id_get_len(id, type);
176 buf = silc_buffer_alloc(random_len + id_len + pk_len);
177 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
178 silc_buffer_format(buf,
179 SILC_STR_UI_XNSTRING(random, random_len),
180 SILC_STR_UI_XNSTRING(id_data, id_len),
181 SILC_STR_UI_XNSTRING(pk, pk_len),
184 ret = silc_calloc(buf->len + 1, sizeof(*ret));
185 memcpy(ret, buf->data, buf->len);
190 silc_buffer_free(buf);
197 /* Generates Authentication Payload with authentication data. This is used
198 to do public key based authentication. This generates the random data
199 and the actual authentication data. Returns NULL on error. */
201 SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
202 SilcPrivateKey private_key,
204 const void *id, SilcIdType type)
206 unsigned char *random;
207 unsigned char auth_data[1024];
214 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
216 /* Get 256 bytes of random data */
217 random = silc_rng_global_get_rn_data(256);
221 /* Encode the auth data */
222 tmp = silc_auth_public_key_encode_data(public_key, random, 256, id, type,
227 /* Allocate PKCS object */
228 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
229 memset(tmp, 0, tmp_len);
233 silc_pkcs_public_key_set(pkcs, public_key);
234 silc_pkcs_private_key_set(pkcs, private_key);
236 /* Compute the hash and the signature. */
237 if (!silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
239 memset(random, 0, 256);
240 memset(tmp, 0, tmp_len);
243 silc_pkcs_free(pkcs);
247 /* Encode Authentication Payload */
248 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, random, 256,
249 auth_data, auth_len);
251 memset(tmp, 0, tmp_len);
252 memset(auth_data, 0, sizeof(auth_data));
253 memset(random, 0, 256);
256 silc_pkcs_free(pkcs);
261 /* Verifies the authentication data. Returns TRUE if authentication was
264 bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
265 SilcPublicKey public_key, SilcHash hash,
266 const void *id, SilcIdType type)
272 SILC_LOG_DEBUG(("Verifying authentication data"));
274 /* Encode auth data */
275 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
279 SILC_LOG_DEBUG(("Authentication failed"));
283 /* Allocate PKCS object */
284 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
285 memset(tmp, 0, tmp_len);
289 silc_pkcs_public_key_set(pkcs, public_key);
291 /* Verify the authentication data */
292 if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
293 payload->auth_len, tmp, tmp_len)) {
295 memset(tmp, 0, tmp_len);
297 silc_pkcs_free(pkcs);
298 SILC_LOG_DEBUG(("Authentication failed"));
302 memset(tmp, 0, tmp_len);
304 silc_pkcs_free(pkcs);
306 SILC_LOG_DEBUG(("Authentication successful"));
311 /* Same as above but the payload is not parsed yet. This will parse it. */
313 bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
315 SilcPublicKey public_key,
317 const void *id, SilcIdType type)
319 SilcAuthPayload auth_payload;
322 auth_payload = silc_auth_payload_parse(payload, payload_len);
324 SILC_LOG_DEBUG(("Authentication failed"));
328 ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
331 silc_auth_payload_free(auth_payload);
336 /* Verifies the authentication data directly from the Authentication
337 Payload. Supports all authentication methods. If the authentication
338 method is passphrase based then the `auth_data' and `auth_data_len'
339 are the passphrase and its length. If the method is public key
340 authentication then the `auth_data' is the SilcPublicKey and the
341 `auth_data_len' is ignored. */
343 bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
344 const void *auth_data, uint32 auth_data_len,
345 SilcHash hash, const void *id, SilcIdType type)
347 SILC_LOG_DEBUG(("Verifying authentication"));
349 if (auth_method != payload->auth_method)
352 switch (payload->auth_method) {
354 /* No authentication */
355 SILC_LOG_DEBUG(("No authentication required"));
358 case SILC_AUTH_PASSWORD:
359 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
360 arguments are not needed. */
361 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
362 SILC_LOG_DEBUG(("Authentication successful"));
367 case SILC_AUTH_PUBLIC_KEY:
368 /* Public key based authentication */
369 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
377 SILC_LOG_DEBUG(("Authentication failed"));
382 /* Same as above but parses the authentication payload before verify. */
384 bool silc_auth_verify_data(const unsigned char *payload, uint32 payload_len,
385 SilcAuthMethod auth_method, const void *auth_data,
386 uint32 auth_data_len, SilcHash hash,
387 const void *id, SilcIdType type)
389 SilcAuthPayload auth_payload;
392 auth_payload = silc_auth_payload_parse(payload, payload_len);
396 ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
399 silc_auth_payload_free(auth_payload);
404 /******************************************************************************
406 Key Agreement Payload
408 ******************************************************************************/
410 /* The Key Agreement protocol structure */
411 struct SilcKeyAgreementPayloadStruct {
413 unsigned char *hostname;
417 /* Parses and returns an allocated Key Agreement payload. */
419 SilcKeyAgreementPayload
420 silc_key_agreement_payload_parse(const unsigned char *payload,
423 SilcBufferStruct buffer;
424 SilcKeyAgreementPayload new;
427 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
429 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
430 new = silc_calloc(1, sizeof(*new));
432 /* Parse the payload */
433 ret = silc_buffer_unformat(&buffer,
434 SILC_STR_UI16_NSTRING_ALLOC(&new->hostname,
436 SILC_STR_UI_INT(&new->port),
446 /* Encodes the Key Agreement protocol and returns the encoded buffer */
448 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
452 uint32 len = hostname ? strlen(hostname) : 0;
454 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
456 buffer = silc_buffer_alloc(2 + len + 4);
457 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
458 silc_buffer_format(buffer,
459 SILC_STR_UI_SHORT(len),
460 SILC_STR_UI_XNSTRING(hostname, len),
461 SILC_STR_UI_INT(port),
467 /* Frees the Key Agreement protocol */
469 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
472 silc_free(payload->hostname);
477 /* Returns the hostname in the payload */
479 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
481 return payload->hostname;
484 /* Returns the port in the payload */
486 uint32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
488 return payload->port;