2010-08-26 10:50:06 +00:00
|
|
|
/*
|
|
|
|
* ac.c -- Check access condition
|
2010-11-02 03:12:58 +00:00
|
|
|
*
|
|
|
|
* Copyright (C) 2010 Free Software Initiative of Japan
|
|
|
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
|
|
|
*
|
|
|
|
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
|
|
|
*
|
|
|
|
* Gnuk is free software: you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
|
|
* License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
2010-08-26 10:50:06 +00:00
|
|
|
*/
|
|
|
|
|
2010-09-04 04:48:26 +00:00
|
|
|
#include "config.h"
|
2010-08-26 10:50:06 +00:00
|
|
|
#include "ch.h"
|
|
|
|
#include "gnuk.h"
|
|
|
|
|
2010-08-30 11:02:22 +00:00
|
|
|
#include "polarssl/config.h"
|
|
|
|
#include "polarssl/sha1.h"
|
|
|
|
|
2010-08-26 10:50:06 +00:00
|
|
|
static uint8_t auth_status = AC_NONE_AUTHORIZED;
|
|
|
|
|
|
|
|
int
|
|
|
|
ac_check_status (uint8_t ac_flag)
|
|
|
|
{
|
|
|
|
if (ac_flag == AC_ALWAYS)
|
|
|
|
return 1;
|
|
|
|
else if (ac_flag == AC_NEVER)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return (ac_flag & auth_status)? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2010-09-09 08:50:34 +00:00
|
|
|
void
|
|
|
|
ac_reset_pso_cds (void)
|
|
|
|
{
|
|
|
|
auth_status &= ~AC_PSO_CDS_AUTHORIZED;
|
|
|
|
}
|
|
|
|
|
2010-10-16 00:22:18 +00:00
|
|
|
uint8_t pw1_keystring[KEYSTRING_SIZE_PW1];
|
|
|
|
|
2010-09-09 08:50:34 +00:00
|
|
|
void
|
|
|
|
ac_reset_pso_other (void)
|
|
|
|
{
|
2010-10-16 00:22:18 +00:00
|
|
|
memset (pw1_keystring, 0, KEYSTRING_SIZE_PW1);
|
2010-09-09 08:50:34 +00:00
|
|
|
auth_status &= ~AC_PSO_OTHER_AUTHORIZED;
|
|
|
|
}
|
|
|
|
|
2010-11-05 07:42:17 +00:00
|
|
|
/*
|
|
|
|
* Verify for "Perform Security Operation : Compute Digital Signature"
|
|
|
|
*/
|
2010-08-26 10:50:06 +00:00
|
|
|
int
|
2010-09-03 15:42:36 +00:00
|
|
|
verify_pso_cds (const uint8_t *pw, int pw_len)
|
2010-08-26 10:50:06 +00:00
|
|
|
{
|
2010-08-30 11:02:22 +00:00
|
|
|
int r;
|
2010-09-03 15:42:36 +00:00
|
|
|
uint8_t keystring[KEYSTRING_SIZE_PW1];
|
2010-08-30 11:02:22 +00:00
|
|
|
|
2010-11-05 07:42:17 +00:00
|
|
|
if (gpg_passwd_locked (PW_ERR_PW1))
|
2010-09-03 15:42:36 +00:00
|
|
|
return 0;
|
|
|
|
|
2010-09-05 16:55:29 +00:00
|
|
|
DEBUG_INFO ("verify_pso_cds\r\n");
|
|
|
|
DEBUG_BYTE (pw_len);
|
|
|
|
|
2010-09-03 15:42:36 +00:00
|
|
|
keystring[0] = pw_len;
|
|
|
|
sha1 (pw, pw_len, keystring+1);
|
2010-10-16 00:22:18 +00:00
|
|
|
if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring+1)) < 0)
|
2010-09-03 15:42:36 +00:00
|
|
|
{
|
2010-11-05 07:42:17 +00:00
|
|
|
gpg_increment_pw_err_counter (PW_ERR_PW1);
|
2010-09-03 15:42:36 +00:00
|
|
|
return r;
|
|
|
|
}
|
2010-11-05 07:42:17 +00:00
|
|
|
else
|
|
|
|
gpg_reset_pw_err_counter (PW_ERR_PW1);
|
2010-08-30 11:02:22 +00:00
|
|
|
|
2010-08-26 10:50:06 +00:00
|
|
|
auth_status |= AC_PSO_CDS_AUTHORIZED;
|
2010-09-03 15:42:36 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-08-26 10:50:06 +00:00
|
|
|
int
|
2010-09-03 15:42:36 +00:00
|
|
|
verify_pso_other (const uint8_t *pw, int pw_len)
|
2010-08-26 10:50:06 +00:00
|
|
|
{
|
2010-10-16 00:22:18 +00:00
|
|
|
const uint8_t *ks_pw1;
|
|
|
|
|
|
|
|
DEBUG_INFO ("verify_pso_other\r\n");
|
2010-09-03 15:42:36 +00:00
|
|
|
|
2010-11-05 07:42:17 +00:00
|
|
|
if (gpg_passwd_locked (PW_ERR_PW1))
|
2010-09-03 15:42:36 +00:00
|
|
|
return 0;
|
|
|
|
|
2010-10-16 00:22:18 +00:00
|
|
|
/*
|
2010-11-05 07:42:17 +00:00
|
|
|
* We check only the length of password string here.
|
2010-10-16 00:22:18 +00:00
|
|
|
* Real check is defered to decrypt/authenticate routines.
|
|
|
|
*/
|
|
|
|
ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
|
|
|
|
if ((ks_pw1 == NULL && pw_len == strlen (OPENPGP_CARD_INITIAL_PW1))
|
|
|
|
|| (ks_pw1 != NULL && pw_len == ks_pw1[0]))
|
|
|
|
{ /* No problem */
|
|
|
|
/*
|
2010-11-05 07:42:17 +00:00
|
|
|
* We don't call gpg_reset_pw_err_counters here, because
|
|
|
|
* password may be wrong.
|
2010-10-16 00:22:18 +00:00
|
|
|
*/
|
|
|
|
pw1_keystring[0] = pw_len;
|
|
|
|
sha1 (pw, pw_len, pw1_keystring+1);
|
|
|
|
auth_status |= AC_PSO_OTHER_AUTHORIZED;
|
|
|
|
return 1;
|
2010-09-03 15:42:36 +00:00
|
|
|
}
|
2010-10-16 00:22:18 +00:00
|
|
|
else
|
2010-09-03 15:42:36 +00:00
|
|
|
{
|
2010-11-05 07:42:17 +00:00
|
|
|
gpg_increment_pw_err_counter (PW_ERR_PW1);
|
2010-10-16 00:22:18 +00:00
|
|
|
return 0;
|
2010-09-03 15:42:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For keystring of PW3, we use SALT+ITER+MD format
|
|
|
|
*/
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
decode_iterate_count (uint8_t x)
|
|
|
|
{
|
|
|
|
return (16UL + ((x) & 15)) << (((x) >> 4) + 6);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
calc_md (int count, const uint8_t *salt, const uint8_t *pw, int pw_len,
|
|
|
|
uint8_t md[KEYSTRING_MD_SIZE])
|
|
|
|
{
|
2010-09-08 05:24:12 +00:00
|
|
|
sha1_context sha1_ctx;
|
|
|
|
|
2010-09-03 15:42:36 +00:00
|
|
|
sha1_starts (&sha1_ctx);
|
|
|
|
|
|
|
|
while (count > pw_len + 8)
|
|
|
|
{
|
|
|
|
sha1_update (&sha1_ctx, salt, 8);
|
|
|
|
sha1_update (&sha1_ctx, pw, pw_len);
|
|
|
|
count -= pw_len + 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count < 8)
|
|
|
|
sha1_update (&sha1_ctx, salt, count);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sha1_update (&sha1_ctx, salt, 8);
|
|
|
|
count -= 8;
|
|
|
|
sha1_update (&sha1_ctx, pw, count);
|
|
|
|
}
|
|
|
|
|
|
|
|
sha1_finish (&sha1_ctx, md);
|
|
|
|
memset (&sha1_ctx, 0, sizeof (sha1_ctx));
|
2010-08-26 10:50:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2010-09-03 15:42:36 +00:00
|
|
|
verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known)
|
2010-08-26 10:50:06 +00:00
|
|
|
{
|
2010-09-03 15:42:36 +00:00
|
|
|
const uint8_t *pw3_keystring;
|
|
|
|
int pw_len;
|
|
|
|
|
2010-11-05 07:42:17 +00:00
|
|
|
if (gpg_passwd_locked (PW_ERR_PW3))
|
2010-09-03 15:42:36 +00:00
|
|
|
return 0;
|
|
|
|
|
2010-09-05 09:10:54 +00:00
|
|
|
pw3_keystring = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
|
2010-09-03 15:42:36 +00:00
|
|
|
if (pw3_keystring != NULL)
|
|
|
|
{
|
|
|
|
int count;
|
|
|
|
uint8_t md[KEYSTRING_MD_SIZE];
|
|
|
|
const uint8_t *salt;
|
|
|
|
|
|
|
|
pw_len = pw3_keystring[0];
|
|
|
|
if ((pw_len_known >= 0 && pw_len_known != pw_len) || pw_len < buf_len)
|
|
|
|
goto failure;
|
|
|
|
|
|
|
|
salt = &pw3_keystring[1];
|
|
|
|
count = decode_iterate_count (pw3_keystring[1+8]);
|
|
|
|
calc_md (count, salt, pw, pw_len, md);
|
|
|
|
|
|
|
|
if (memcmp (md, &pw3_keystring[1+8+1], KEYSTRING_MD_SIZE) != 0)
|
|
|
|
{
|
|
|
|
failure:
|
2010-11-05 07:42:17 +00:00
|
|
|
gpg_increment_pw_err_counter (PW_ERR_PW3);
|
2010-09-03 15:42:36 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2010-11-05 07:42:17 +00:00
|
|
|
else
|
|
|
|
/* OK, the user is now authenticated */
|
|
|
|
gpg_reset_pw_err_counter (PW_ERR_PW3);
|
2010-09-03 15:42:36 +00:00
|
|
|
}
|
2010-08-26 10:50:06 +00:00
|
|
|
else
|
2010-10-28 00:53:41 +00:00
|
|
|
/* For empty PW3, pass phrase should be OPENPGP_CARD_INITIAL_PW3 */
|
2010-09-03 15:42:36 +00:00
|
|
|
{
|
2010-10-28 00:53:41 +00:00
|
|
|
if ((pw_len_known >=0 && pw_len_known != strlen (OPENPGP_CARD_INITIAL_PW3))
|
2010-11-08 05:06:54 +00:00
|
|
|
|| buf_len < (int)strlen (OPENPGP_CARD_INITIAL_PW3)
|
2010-11-02 03:12:58 +00:00
|
|
|
|| strncmp ((const char *)pw, OPENPGP_CARD_INITIAL_PW3,
|
|
|
|
strlen (OPENPGP_CARD_INITIAL_PW3)) != 0)
|
2010-09-03 15:42:36 +00:00
|
|
|
/* It is failure, but we don't try to lock for the case of empty PW3 */
|
|
|
|
return -1;
|
|
|
|
|
2010-11-03 04:47:28 +00:00
|
|
|
pw_len = strlen (OPENPGP_CARD_INITIAL_PW3);
|
2010-09-03 15:42:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return pw_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gpg_set_pw3 (const uint8_t *newpw, int newpw_len)
|
|
|
|
{
|
|
|
|
uint8_t ks[KEYSTRING_SIZE_PW3];
|
|
|
|
uint32_t random;
|
|
|
|
|
|
|
|
ks[0] = newpw_len;
|
|
|
|
random = get_random ();
|
|
|
|
memcpy (&ks[1], &random, sizeof (random));
|
|
|
|
random = get_random ();
|
|
|
|
memcpy (&ks[5], &random, sizeof (random));
|
|
|
|
ks[9] = 0x60; /* 65536 iterations */
|
|
|
|
|
|
|
|
calc_md (65536, &ks[1], newpw, newpw_len, &ks[10]);
|
2010-09-05 09:10:54 +00:00
|
|
|
gpg_do_write_simple (NR_DO_KEYSTRING_PW3, ks, KEYSTRING_SIZE_PW3);
|
2010-09-03 15:42:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE];
|
|
|
|
|
|
|
|
int
|
|
|
|
verify_admin (const uint8_t *pw, int pw_len)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = verify_admin_0 (pw, pw_len, pw_len);
|
|
|
|
if (r <= 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
sha1 (pw, pw_len, keystring_md_pw3);
|
2010-08-26 10:50:06 +00:00
|
|
|
auth_status |= AC_ADMIN_AUTHORIZED;
|
2010-09-03 15:42:36 +00:00
|
|
|
return 1;
|
2010-08-26 10:50:06 +00:00
|
|
|
}
|