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,
96 SILC_LOG_DEBUG(("Encoding Authentication Payload"));
98 len = 2 + 2 + 2 + random_len + 2 + auth_len;
99 buffer = silc_buffer_alloc_size(len);
102 silc_buffer_format(buffer,
103 SILC_STR_UI_SHORT(len),
104 SILC_STR_UI_SHORT(method),
105 SILC_STR_UI_SHORT(random_len),
106 SILC_STR_UI_XNSTRING(random_data, random_len),
107 SILC_STR_UI_SHORT(auth_len),
108 SILC_STR_UI_XNSTRING(auth_data, auth_len),
114 /* Frees authentication payload. */
116 void silc_auth_payload_free(SilcAuthPayload payload)
119 if (payload->random_data) {
120 memset(payload->random_data, 0, payload->random_len);
121 silc_free(payload->random_data);
123 if (payload->auth_data) {
124 memset(payload->auth_data, 0, payload->auth_len);
125 silc_free(payload->auth_data);
131 /* Get authentication method */
133 SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload)
135 return payload->auth_method;
138 /* Get the authentication data */
140 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
141 SilcUInt32 *auth_len)
144 *auth_len = payload->auth_len;
146 return payload->auth_data;
149 /******************************************************************************
151 Authentication Routines
153 ******************************************************************************/
155 /* Encodes the authentication data for hashing and signing as the protocol
158 static unsigned char *
159 silc_auth_public_key_encode_data(SilcPublicKey public_key,
160 const unsigned char *random,
161 SilcUInt32 random_len, const void *id,
162 SilcIdType type, SilcUInt32 *ret_len)
165 unsigned char *pk, *id_data, *ret;
166 SilcUInt32 pk_len, id_len;
168 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
172 id_data = silc_id_id2str(id, type);
177 id_len = silc_id_get_len(id, type);
179 buf = silc_buffer_alloc_size(random_len + id_len + pk_len);
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_memdup(buf->data, buf->len);
198 silc_buffer_free(buf);
205 /* Generates Authentication Payload with authentication data. This is used
206 to do public key based authentication. This generates the random data
207 and the actual authentication data. Returns NULL on error. */
209 SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
210 SilcPrivateKey private_key,
212 const void *id, SilcIdType type)
214 unsigned char *random;
215 unsigned char auth_data[1024];
222 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
224 /* Get 256 bytes of random data */
225 random = silc_rng_global_get_rn_data(256);
229 /* Encode the auth data */
230 tmp = silc_auth_public_key_encode_data(public_key, random, 256, id, type,
235 /* Allocate PKCS object */
236 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
237 memset(tmp, 0, tmp_len);
241 silc_pkcs_public_key_set(pkcs, public_key);
242 silc_pkcs_private_key_set(pkcs, private_key);
244 /* Compute the hash and the signature. */
245 if (!silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
247 memset(random, 0, 256);
248 memset(tmp, 0, tmp_len);
251 silc_pkcs_free(pkcs);
255 /* Encode Authentication Payload */
256 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, random, 256,
257 auth_data, auth_len);
259 memset(tmp, 0, tmp_len);
260 memset(auth_data, 0, sizeof(auth_data));
261 memset(random, 0, 256);
264 silc_pkcs_free(pkcs);
269 /* Verifies the authentication data. Returns TRUE if authentication was
272 bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
273 SilcPublicKey public_key, SilcHash hash,
274 const void *id, SilcIdType type)
280 SILC_LOG_DEBUG(("Verifying authentication data"));
282 /* Encode auth data */
283 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
287 SILC_LOG_DEBUG(("Authentication failed"));
291 /* Allocate PKCS object */
292 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
293 memset(tmp, 0, tmp_len);
297 silc_pkcs_public_key_set(pkcs, public_key);
299 /* Verify the authentication data */
300 if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
301 payload->auth_len, tmp, tmp_len)) {
303 memset(tmp, 0, tmp_len);
305 silc_pkcs_free(pkcs);
306 SILC_LOG_DEBUG(("Authentication failed"));
310 memset(tmp, 0, tmp_len);
312 silc_pkcs_free(pkcs);
314 SILC_LOG_DEBUG(("Authentication successful"));
319 /* Same as above but the payload is not parsed yet. This will parse it. */
321 bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
322 SilcUInt32 payload_len,
323 SilcPublicKey public_key,
325 const void *id, SilcIdType type)
327 SilcAuthPayload auth_payload;
330 auth_payload = silc_auth_payload_parse(payload, payload_len);
332 SILC_LOG_DEBUG(("Authentication failed"));
336 ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
339 silc_auth_payload_free(auth_payload);
344 /* Verifies the authentication data directly from the Authentication
345 Payload. Supports all authentication methods. If the authentication
346 method is passphrase based then the `auth_data' and `auth_data_len'
347 are the passphrase and its length. If the method is public key
348 authentication then the `auth_data' is the SilcPublicKey and the
349 `auth_data_len' is ignored. */
351 bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
352 const void *auth_data, SilcUInt32 auth_data_len,
353 SilcHash hash, const void *id, SilcIdType type)
355 SILC_LOG_DEBUG(("Verifying authentication"));
357 if (auth_method != payload->auth_method)
360 switch (payload->auth_method) {
362 /* No authentication */
363 SILC_LOG_DEBUG(("No authentication required"));
366 case SILC_AUTH_PASSWORD:
367 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
368 arguments are not needed. */
369 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
370 SILC_LOG_DEBUG(("Authentication successful"));
375 case SILC_AUTH_PUBLIC_KEY:
376 /* Public key based authentication */
377 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
385 SILC_LOG_DEBUG(("Authentication failed"));
390 /* Same as above but parses the authentication payload before verify. */
392 bool silc_auth_verify_data(const unsigned char *payload, SilcUInt32 payload_len,
393 SilcAuthMethod auth_method, const void *auth_data,
394 SilcUInt32 auth_data_len, SilcHash hash,
395 const void *id, SilcIdType type)
397 SilcAuthPayload auth_payload;
400 auth_payload = silc_auth_payload_parse(payload, payload_len);
404 ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
407 silc_auth_payload_free(auth_payload);
412 /******************************************************************************
414 Key Agreement Payload
416 ******************************************************************************/
418 /* The Key Agreement protocol structure */
419 struct SilcKeyAgreementPayloadStruct {
420 SilcUInt16 hostname_len;
421 unsigned char *hostname;
425 /* Parses and returns an allocated Key Agreement payload. */
427 SilcKeyAgreementPayload
428 silc_key_agreement_payload_parse(const unsigned char *payload,
429 SilcUInt32 payload_len)
431 SilcBufferStruct buffer;
432 SilcKeyAgreementPayload newp;
435 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
437 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
438 newp = silc_calloc(1, sizeof(*newp));
442 /* Parse the payload */
443 ret = silc_buffer_unformat(&buffer,
444 SILC_STR_UI16_NSTRING_ALLOC(&newp->hostname,
445 &newp->hostname_len),
446 SILC_STR_UI_INT(&newp->port),
456 /* Encodes the Key Agreement protocol and returns the encoded buffer */
458 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
462 SilcUInt32 len = hostname ? strlen(hostname) : 0;
464 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
466 buffer = silc_buffer_alloc_size(2 + len + 4);
469 silc_buffer_format(buffer,
470 SILC_STR_UI_SHORT(len),
471 SILC_STR_UI_XNSTRING(hostname, len),
472 SILC_STR_UI_INT(port),
478 /* Frees the Key Agreement protocol */
480 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
483 silc_free(payload->hostname);
488 /* Returns the hostname in the payload */
490 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
492 return payload->hostname;
495 /* Returns the port in the payload */
497 SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
499 return payload->port;