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,
211 SilcRng rng, SilcHash hash,
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 */
226 random = silc_rng_get_rn_data(rng, 256);
228 random = silc_rng_global_get_rn_data(256);
232 /* Encode the auth data */
233 tmp = silc_auth_public_key_encode_data(public_key, random, 256, id, type,
238 /* Allocate PKCS object */
239 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
240 memset(tmp, 0, tmp_len);
244 silc_pkcs_public_key_set(pkcs, public_key);
245 silc_pkcs_private_key_set(pkcs, private_key);
247 /* Compute the hash and the signature. */
248 if (!silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
250 memset(random, 0, 256);
251 memset(tmp, 0, tmp_len);
254 silc_pkcs_free(pkcs);
258 /* Encode Authentication Payload */
259 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, random, 256,
260 auth_data, auth_len);
262 memset(tmp, 0, tmp_len);
263 memset(auth_data, 0, sizeof(auth_data));
264 memset(random, 0, 256);
267 silc_pkcs_free(pkcs);
272 /* Verifies the authentication data. Returns TRUE if authentication was
275 bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
276 SilcPublicKey public_key, SilcHash hash,
277 const void *id, SilcIdType type)
283 SILC_LOG_DEBUG(("Verifying authentication data"));
285 /* Encode auth data */
286 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
290 SILC_LOG_DEBUG(("Authentication failed"));
294 /* Allocate PKCS object */
295 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
296 memset(tmp, 0, tmp_len);
300 silc_pkcs_public_key_set(pkcs, public_key);
302 /* Verify the authentication data */
303 if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
304 payload->auth_len, tmp, tmp_len)) {
306 memset(tmp, 0, tmp_len);
308 silc_pkcs_free(pkcs);
309 SILC_LOG_DEBUG(("Authentication failed"));
313 memset(tmp, 0, tmp_len);
315 silc_pkcs_free(pkcs);
317 SILC_LOG_DEBUG(("Authentication successful"));
322 /* Same as above but the payload is not parsed yet. This will parse it. */
324 bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
325 SilcUInt32 payload_len,
326 SilcPublicKey public_key,
328 const void *id, SilcIdType type)
330 SilcAuthPayload auth_payload;
333 auth_payload = silc_auth_payload_parse(payload, payload_len);
335 SILC_LOG_DEBUG(("Authentication failed"));
339 ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
342 silc_auth_payload_free(auth_payload);
347 /* Verifies the authentication data directly from the Authentication
348 Payload. Supports all authentication methods. If the authentication
349 method is passphrase based then the `auth_data' and `auth_data_len'
350 are the passphrase and its length. If the method is public key
351 authentication then the `auth_data' is the SilcPublicKey and the
352 `auth_data_len' is ignored. */
354 bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
355 const void *auth_data, SilcUInt32 auth_data_len,
356 SilcHash hash, const void *id, SilcIdType type)
358 SILC_LOG_DEBUG(("Verifying authentication"));
360 if (auth_method != payload->auth_method)
363 switch (payload->auth_method) {
365 /* No authentication */
366 SILC_LOG_DEBUG(("No authentication required"));
369 case SILC_AUTH_PASSWORD:
370 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
371 arguments are not needed. */
372 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
373 SILC_LOG_DEBUG(("Authentication successful"));
378 case SILC_AUTH_PUBLIC_KEY:
379 /* Public key based authentication */
380 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
388 SILC_LOG_DEBUG(("Authentication failed"));
393 /* Same as above but parses the authentication payload before verify. */
395 bool silc_auth_verify_data(const unsigned char *payload, SilcUInt32 payload_len,
396 SilcAuthMethod auth_method, const void *auth_data,
397 SilcUInt32 auth_data_len, SilcHash hash,
398 const void *id, SilcIdType type)
400 SilcAuthPayload auth_payload;
403 auth_payload = silc_auth_payload_parse(payload, payload_len);
407 ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
410 silc_auth_payload_free(auth_payload);
415 /******************************************************************************
417 Key Agreement Payload
419 ******************************************************************************/
421 /* The Key Agreement protocol structure */
422 struct SilcKeyAgreementPayloadStruct {
423 SilcUInt16 hostname_len;
424 unsigned char *hostname;
428 /* Parses and returns an allocated Key Agreement payload. */
430 SilcKeyAgreementPayload
431 silc_key_agreement_payload_parse(const unsigned char *payload,
432 SilcUInt32 payload_len)
434 SilcBufferStruct buffer;
435 SilcKeyAgreementPayload newp;
438 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
440 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
441 newp = silc_calloc(1, sizeof(*newp));
445 /* Parse the payload */
446 ret = silc_buffer_unformat(&buffer,
447 SILC_STR_UI16_NSTRING_ALLOC(&newp->hostname,
448 &newp->hostname_len),
449 SILC_STR_UI_INT(&newp->port),
459 /* Encodes the Key Agreement protocol and returns the encoded buffer */
461 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
465 SilcUInt32 len = hostname ? strlen(hostname) : 0;
467 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
469 buffer = silc_buffer_alloc_size(2 + len + 4);
472 silc_buffer_format(buffer,
473 SILC_STR_UI_SHORT(len),
474 SILC_STR_UI_XNSTRING(hostname, len),
475 SILC_STR_UI_INT(port),
481 /* Frees the Key Agreement protocol */
483 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
486 silc_free(payload->hostname);
491 /* Returns the hostname in the payload */
493 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
495 return payload->hostname;
498 /* Returns the port in the payload */
500 SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
502 return payload->port;