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,
46 SilcBufferStruct buffer;
50 SILC_LOG_DEBUG(("Parsing Authentication Payload"));
52 silc_buffer_set(&buffer, data, data_len);
54 new = silc_calloc(1, sizeof(*new));
56 /* Parse the payload */
57 ret = silc_buffer_unformat(&buffer,
58 SILC_STR_UI_SHORT(&new->len),
59 SILC_STR_UI_SHORT(&new->auth_method),
60 SILC_STR_UI16_NSTRING_ALLOC(&new->random_data,
62 SILC_STR_UI16_NSTRING_ALLOC(&new->auth_data,
70 if (new->len != buffer.len) {
71 silc_auth_payload_free(new);
75 /* If password authentication, random data must not be set */
76 if (new->auth_method == SILC_AUTH_PASSWORD && new->random_len) {
77 silc_auth_payload_free(new);
84 /* Encodes authentication payload into buffer and returns it */
86 SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
87 unsigned char *random_data,
89 unsigned char *auth_data,
95 SILC_LOG_DEBUG(("Encoding Authentication Payload"));
97 len = 2 + 2 + 2 + random_len + 2 + auth_len;
98 buffer = silc_buffer_alloc(len);
99 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
100 silc_buffer_format(buffer,
101 SILC_STR_UI_SHORT(len),
102 SILC_STR_UI_SHORT(method),
103 SILC_STR_UI_SHORT(random_len),
104 SILC_STR_UI_XNSTRING(random_data, random_len),
105 SILC_STR_UI_SHORT(auth_len),
106 SILC_STR_UI_XNSTRING(auth_data, auth_len),
112 /* Frees authentication payload. */
114 void silc_auth_payload_free(SilcAuthPayload payload)
117 if (payload->random_data) {
118 memset(payload->random_data, 0, payload->random_len);
119 silc_free(payload->random_data);
121 if (payload->auth_data) {
122 memset(payload->auth_data, 0, payload->auth_len);
123 silc_free(payload->auth_data);
129 /* Get authentication method */
131 SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload)
133 return payload->auth_method;
136 /* Get the authentication data */
138 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
142 *auth_len = payload->auth_len;
144 return payload->auth_data;
147 /******************************************************************************
149 Authentication Routines
151 ******************************************************************************/
153 /* Encodes the authentication data for hashing and signing as the protocol
156 static unsigned char *
157 silc_auth_public_key_encode_data(SilcPublicKey public_key,
158 unsigned char *random,
159 uint32 random_len, void *id,
160 SilcIdType type, uint32 *ret_len)
163 unsigned char *pk, *id_data, *ret;
164 uint32 pk_len, id_len;
166 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
170 id_data = silc_id_id2str(id, type);
175 id_len = silc_id_get_len(id, type);
177 buf = silc_buffer_alloc(random_len + id_len + pk_len);
178 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
179 silc_buffer_format(buf,
180 SILC_STR_UI_XNSTRING(random, random_len),
181 SILC_STR_UI_XNSTRING(id_data, id_len),
182 SILC_STR_UI_XNSTRING(pk, pk_len),
185 ret = silc_calloc(buf->len + 1, sizeof(*ret));
186 memcpy(ret, buf->data, buf->len);
191 silc_buffer_free(buf);
198 /* Generates Authentication Payload with authentication data. This is used
199 to do public key based authentication. This generates the random data
200 and the actual authentication data. Returns NULL on error. */
202 SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
203 SilcPrivateKey private_key,
205 void *id, SilcIdType type)
207 unsigned char *random;
208 unsigned char auth_data[1024];
215 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
217 /* Get 256 bytes of random data */
218 random = silc_rng_global_get_rn_data(256);
222 /* Encode the auth data */
223 tmp = silc_auth_public_key_encode_data(public_key, random, 256, id, type,
228 /* Allocate PKCS object */
229 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
230 memset(tmp, 0, tmp_len);
234 silc_pkcs_public_key_set(pkcs, public_key);
235 silc_pkcs_private_key_set(pkcs, private_key);
237 /* Compute the hash and the signature. */
238 if (!silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
240 memset(random, 0, 256);
241 memset(tmp, 0, tmp_len);
244 silc_pkcs_free(pkcs);
248 /* Encode Authentication Payload */
249 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, random, 256,
250 auth_data, auth_len);
252 memset(tmp, 0, tmp_len);
253 memset(auth_data, 0, sizeof(auth_data));
254 memset(random, 0, 256);
257 silc_pkcs_free(pkcs);
262 /* Verifies the authentication data. Returns TRUE if authentication was
265 int silc_auth_public_key_auth_verify(SilcAuthPayload payload,
266 SilcPublicKey public_key, SilcHash hash,
267 void *id, SilcIdType type)
273 SILC_LOG_DEBUG(("Verifying authentication data"));
275 /* Encode auth data */
276 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
280 SILC_LOG_DEBUG(("Authentication failed"));
284 /* Allocate PKCS object */
285 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
286 memset(tmp, 0, tmp_len);
290 silc_pkcs_public_key_set(pkcs, public_key);
292 /* Verify the authentication data */
293 if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
294 payload->auth_len, tmp, tmp_len)) {
296 memset(tmp, 0, tmp_len);
298 silc_pkcs_free(pkcs);
299 SILC_LOG_DEBUG(("Authentication failed"));
303 memset(tmp, 0, tmp_len);
305 silc_pkcs_free(pkcs);
307 SILC_LOG_DEBUG(("Authentication successful"));
312 /* Same as above but the payload is not parsed yet. This will parse it. */
314 int silc_auth_public_key_auth_verify_data(SilcBuffer payload,
315 SilcPublicKey public_key,
317 void *id, SilcIdType type)
319 SilcAuthPayload auth_payload;
322 auth_payload = silc_auth_payload_parse(payload->data, 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 int silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
344 void *auth_data, uint32 auth_data_len,
345 SilcHash hash, 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, payload->auth_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 int silc_auth_verify_data(unsigned char *payload, uint32 payload_len,
385 SilcAuthMethod auth_method, void *auth_data,
386 uint32 auth_data_len, SilcHash hash,
387 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 silc_key_agreement_payload_parse(SilcBuffer buffer)
421 SilcKeyAgreementPayload new;
424 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
426 new = silc_calloc(1, sizeof(*new));
428 /* Parse the payload */
429 ret = silc_buffer_unformat(buffer,
430 SILC_STR_UI16_NSTRING_ALLOC(&new->hostname,
432 SILC_STR_UI_INT(&new->port),
442 /* Encodes the Key Agreement protocol and returns the encoded buffer */
444 SilcBuffer silc_key_agreement_payload_encode(char *hostname,
448 uint32 len = hostname ? strlen(hostname) : 0;
450 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
452 buffer = silc_buffer_alloc(2 + len + 4);
453 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
454 silc_buffer_format(buffer,
455 SILC_STR_UI_SHORT(len),
456 SILC_STR_UI_XNSTRING(hostname, len),
457 SILC_STR_UI_INT(port),
463 /* Frees the Key Agreement protocol */
465 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
468 silc_free(payload->hostname);
473 /* Returns the hostname in the payload */
475 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
477 return payload->hostname;
480 /* Returns the port in the payload */
482 uint32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
484 return payload->port;