Added certificate update functionality

git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@2593 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
sth 2005-09-15 19:40:20 +00:00
parent e15c54e1c5
commit 00be34c4a2
3 changed files with 200 additions and 1 deletions

View File

@ -333,6 +333,15 @@ extern int sc_pkcs15init_change_attrib(struct sc_pkcs15_card *p15card,
extern int sc_pkcs15init_delete_object(sc_pkcs15_card_t *p15card,
sc_profile_t *profile,
sc_pkcs15_object_t *obj);
/* Replace an existing cert with a new one, which is assumed to be
* compatible with the correcsponding private key (e.g. the old and
* new cert should have the same public key).
*/
extern int sc_pkcs15init_update_certificate(sc_pkcs15_card_t *p15card,
sc_profile_t *profile,
sc_pkcs15_object_t *obj,
const unsigned char *rawcert,
int certlen);
extern int sc_pkcs15init_create_file(struct sc_profile *,
struct sc_card *, struct sc_file *);

View File

@ -2582,6 +2582,82 @@ int sc_pkcs15init_delete_object(sc_pkcs15_card_t *p15card,
return r;
}
int
sc_pkcs15init_update_certificate(sc_pkcs15_card_t *p15card,
sc_profile_t *profile,
sc_pkcs15_object_t *obj,
const unsigned char *rawcert, int certlen)
{
sc_file_t *file = NULL, *parent = NULL;
sc_path_t *path = &((sc_pkcs15_cert_info_t *)obj->data)->path;
int r;
/* Set the SO PIN reference from card */
if ((r = set_so_pin_from_card(p15card, profile)) < 0)
return r;
r = sc_select_file(p15card->card, path, &file);
if (r < 0)
return r;
/* If the new cert doesn't fit in the EF, delete it and make the same, but bigger EF */
if (file->size < certlen) {
if ((r = sc_pkcs15init_delete_by_path(profile, p15card->card, path)) < 0)
goto done;
file->size = certlen;
if ((r = do_select_parent(profile, p15card->card, file, &parent)) < 0
|| (r = sc_pkcs15init_authenticate(profile, p15card->card,
parent, SC_AC_OP_CREATE)) < 0)
goto done;
if ((r = sc_create_file(p15card->card, file)) < 0)
goto done;
}
/* Write the new cert */
if ((r = sc_pkcs15init_authenticate(profile, p15card->card, file, SC_AC_OP_UPDATE)) < 0)
goto done;
if ((r = sc_select_file(p15card->card, path, NULL)) < 0)
goto done;
if ((r = sc_update_binary(p15card->card, 0, rawcert, certlen, 0)) < 0)
goto done;
/* Fill the remaining space in the EF (if any) with zeros */
if (certlen < file->size) {
unsigned char *tmp = (unsigned char *) calloc(file->size - certlen, 1);
if (tmp == NULL) {
r = SC_ERROR_OUT_OF_MEMORY;
goto done;
}
r = sc_update_binary(p15card->card, certlen, tmp, file->size - certlen, 0);
free(tmp);
}
if (r >= 0) {
/* Update the CDF entry */
path = &((sc_pkcs15_cert_info_t *)obj->data)->path;
if (file->size != certlen) {
path->index = 0;
path->count = certlen;
}
else
path->count = -1;
r = sc_pkcs15init_update_any_df(p15card, profile, obj->df, 0);
}
/* mark card as dirty */
profile->dirty = 1;
done:
if (file)
sc_file_free(file);
if (parent)
sc_file_free(parent);
return r;
}
/*
* PIN verification
*/

View File

@ -73,6 +73,7 @@ static int do_generate_key(struct sc_profile *, const char *);
static int do_store_private_key(struct sc_profile *);
static int do_store_public_key(struct sc_profile *, EVP_PKEY *);
static int do_store_certificate(struct sc_profile *);
static int do_update_certificate(struct sc_profile *);
static int do_convert_private_key(struct sc_pkcs15_prkey *, EVP_PKEY *);
static int do_convert_public_key(struct sc_pkcs15_pubkey *, EVP_PKEY *);
static int do_convert_cert(sc_pkcs15_der_t *, X509 *);
@ -137,6 +138,7 @@ const struct option options[] = {
{ "store-private-key", required_argument, 0, 'S' },
{ "store-public-key", required_argument, 0, OPT_PUBKEY },
{ "store-certificate", required_argument, 0, 'X' },
{ "update-certificate", required_argument, 0, 'U' },
{ "store-data", required_argument, 0, 'W' },
{ "delete-objects", required_argument, 0, 'D' },
@ -188,6 +190,7 @@ const char * option_help[] = {
"Store private key",
"Store public key",
"Store an X.509 certificate",
"Update an X.509 certificate (carefull with mail decryption certs!!)",
"Store a data object",
"Delete object(s) (use \"help\" for more information)",
@ -205,7 +208,7 @@ const char * option_help[] = {
"Specify user cert label (use with --store-private-key)",
"Specify application id of data object (use with --store-data-object)",
"Output public portion of generated key to file",
"Specify key file format (default PEM)",
"Specify key/cert file format: PEM (=default), DER or PKCS12",
"Specify passphrase for unlocking secret key",
"Mark certificate as a CA certificate",
"Specify X.509 key usage (use \"--key-usage help\" for more information)",
@ -239,6 +242,7 @@ enum {
ACTION_STORE_PRIVKEY,
ACTION_STORE_PUBKEY,
ACTION_STORE_CERT,
ACTION_UPDATE_CERT,
ACTION_STORE_DATA,
ACTION_FINALIZE_CARD,
ACTION_DELETE_OBJECTS,
@ -255,6 +259,7 @@ static const char *action_names[] = {
"store private key",
"store public key",
"store certificate",
"update certificate",
"store data object",
"finalizing card",
"delete object(s)"
@ -417,6 +422,9 @@ main(int argc, char **argv)
case ACTION_STORE_CERT:
r = do_store_certificate(profile);
break;
case ACTION_UPDATE_CERT:
r = do_update_certificate(profile);
break;
case ACTION_STORE_DATA:
r = do_store_data_object(profile);
break;
@ -906,6 +914,108 @@ do_store_certificate(struct sc_profile *profile)
return r;
}
static int
do_read_check_certificate(sc_pkcs15_cert_t *sc_oldcert,
const char *filename, const char *format, sc_pkcs15_der_t *newcert_raw)
{
X509 *oldcert, *newcert;
EVP_PKEY *oldpk, *newpk;
u8 *ptr;
int r;
/* Get the public key from the old cert */
ptr = sc_oldcert->data;
oldcert = d2i_X509(NULL, &ptr, sc_oldcert->data_len);
if (oldcert == NULL)
return SC_ERROR_INTERNAL;
/* Read the new cert from file and get it's public key */
r = do_read_certificate(filename, format, &newcert);
if (r < 0) {
X509_free(oldcert);
return r;
}
oldpk = X509_get_pubkey(oldcert);
newpk = X509_get_pubkey(newcert);
/* Compare the public keys, there's no high level openssl function for this(?) */
r = SC_ERROR_INVALID_ARGUMENTS;
if (oldpk->type == newpk->type)
{
if ((oldpk->type == EVP_PKEY_DSA) &&
!BN_cmp(oldpk->pkey.dsa->p, newpk->pkey.dsa->p) &&
!BN_cmp(oldpk->pkey.dsa->q, newpk->pkey.dsa->q) &&
!BN_cmp(oldpk->pkey.dsa->g, newpk->pkey.dsa->g))
r = 0;
else if ((oldpk->type == EVP_PKEY_RSA) &&
!BN_cmp(oldpk->pkey.rsa->n, newpk->pkey.rsa->n) &&
!BN_cmp(oldpk->pkey.rsa->e, newpk->pkey.rsa->e))
r = 0;
}
EVP_PKEY_free(newpk);
EVP_PKEY_free(oldpk);
X509_free(oldcert);
if (r == 0)
r = do_convert_cert(newcert_raw, newcert);
else
error("the public keys in the old and new certificate differ");
X509_free(newcert);
return r;
}
/*
* Update an existing certificate with a new certificate having
* the same public key.
*/
static int
do_update_certificate(struct sc_profile *profile)
{
sc_pkcs15_id_t id;
sc_pkcs15_object_t *obj;
sc_pkcs15_cert_info_t *certinfo;
sc_pkcs15_cert_t *oldcert = NULL;
X509 *newcert = NULL;
sc_pkcs15_der_t newcert_raw;
int r;
set_userpin_ref();
if (opt_objectid == NULL) {
error("no ID given for the cert: use --id");
return SC_ERROR_INVALID_ARGUMENTS;
}
sc_pkcs15_format_id(opt_objectid, &id);
if (sc_pkcs15_find_cert_by_id(p15card, &id, &obj) != 0) {
error("Couldn't find the cert with ID %s\n", opt_objectid);
return SC_ERROR_OBJECT_NOT_FOUND;
}
certinfo = (sc_pkcs15_cert_info_t *) obj->data;
r = sc_pkcs15_read_certificate(p15card, certinfo, &oldcert);
if (r < 0)
return r;
newcert_raw.value = NULL;
r = do_read_check_certificate(oldcert, opt_infile, opt_format, &newcert_raw);
sc_pkcs15_free_certificate(oldcert);
if (r < 0)
return r;
r = sc_pkcs15init_update_certificate(p15card, profile, obj,
newcert_raw.value, newcert_raw.len);
if (newcert_raw.value)
free(newcert_raw.value);
return r;
}
/*
* Download data object to card
*/
@ -2146,6 +2256,10 @@ handle_option(const struct option *opt)
this_action = ACTION_STORE_CERT;
opt_infile = optarg;
break;
case 'U':
this_action = ACTION_UPDATE_CERT;
opt_infile = optarg;
break;
case 'W':
this_action = ACTION_STORE_DATA;
opt_infile = optarg;