Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F34109904
card-p15.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
12 KB
Subscribers
None
card-p15.c
View Options
/* card-p15.c - PKCS-15 based card access
* Copyright (C) 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG 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 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include
<config.h>
#include
<errno.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
<time.h>
#ifdef HAVE_OPENSC
#include
<opensc/pkcs15.h>
#include
"scdaemon.h"
#include
<ksba.h>
#include
"card-common.h"
struct
p15private_s
{
int
n_prkey_rsa_objs
;
struct
sc_pkcs15_object
*
prkey_rsa_objs
[
32
];
int
n_cert_objs
;
struct
sc_pkcs15_object
*
cert_objs
[
32
];
};
/* Allocate private data. */
static
int
init_private_data
(
CARD
card
)
{
struct
p15private_s
*
priv
;
int
rc
;
if
(
card
->
p15priv
)
return
0
;
/* already done. */
priv
=
xtrycalloc
(
1
,
sizeof
*
priv
);
if
(
!
priv
)
return
out_of_core
();
/* OpenSC (0.7.0) is a bit strange in that the get_objects functions
tries to be a bit too clever and implicitly does an enumeration
which eventually leads to the fact that every call to this
fucntion returns one more macthing object. The old code in
p15_enum_keypairs assume that it would alwyas return the same
numer of objects and used this to figure out what the last object
enumerated is. We now do an enum_objects just once and keep it
in the private data. */
rc
=
sc_pkcs15_get_objects
(
card
->
p15card
,
SC_PKCS15_TYPE_PRKEY_RSA
,
priv
->
prkey_rsa_objs
,
DIM
(
priv
->
prkey_rsa_objs
));
if
(
rc
<
0
)
{
log_error
(
"private keys enumeration failed: %s
\n
"
,
sc_strerror
(
rc
));
xfree
(
priv
);
return
gpg_error
(
GPG_ERR_CARD
);
}
priv
->
n_prkey_rsa_objs
=
rc
;
/* Read all certificate objects. */
rc
=
sc_pkcs15_get_objects
(
card
->
p15card
,
SC_PKCS15_TYPE_CERT_X509
,
priv
->
cert_objs
,
DIM
(
priv
->
cert_objs
));
if
(
rc
<
0
)
{
log_error
(
"private keys enumeration failed: %s
\n
"
,
sc_strerror
(
rc
));
xfree
(
priv
);
return
gpg_error
(
GPG_ERR_CARD
);
}
priv
->
n_cert_objs
=
rc
;
card
->
p15priv
=
priv
;
return
0
;
}
/* Release private data used in this module. */
void
p15_release_private_data
(
CARD
card
)
{
if
(
!
card
->
p15priv
)
return
;
xfree
(
card
->
p15priv
);
card
->
p15priv
=
NULL
;
}
/* See card.c for interface description */
static
int
p15_enum_keypairs
(
CARD
card
,
int
idx
,
unsigned
char
*
keygrip
,
char
**
keyid
)
{
int
rc
;
struct
p15private_s
*
priv
;
struct
sc_pkcs15_object
*
tmpobj
;
int
nobjs
;
struct
sc_pkcs15_prkey_info
*
pinfo
;
struct
sc_pkcs15_cert_info
*
certinfo
;
struct
sc_pkcs15_cert
*
certder
;
ksba_cert_t
cert
;
rc
=
init_private_data
(
card
);
if
(
rc
)
return
rc
;
priv
=
card
->
p15priv
;
nobjs
=
priv
->
n_prkey_rsa_objs
;
rc
=
0
;
if
(
idx
>=
nobjs
)
return
-1
;
pinfo
=
priv
->
prkey_rsa_objs
[
idx
]
->
data
;
/* now we need to read the certificate so that we can calculate the
keygrip */
rc
=
sc_pkcs15_find_cert_by_id
(
card
->
p15card
,
&
pinfo
->
id
,
&
tmpobj
);
if
(
rc
)
{
log_info
(
"certificate for private key %d not found: %s
\n
"
,
idx
,
sc_strerror
(
rc
));
/* note, that we return the ID anyway */
rc
=
gpg_error
(
GPG_ERR_MISSING_CERT
);
goto
return_keyid
;
}
certinfo
=
tmpobj
->
data
;
rc
=
sc_pkcs15_read_certificate
(
card
->
p15card
,
certinfo
,
&
certder
);
if
(
rc
)
{
log_info
(
"failed to read certificate for private key %d: %s
\n
"
,
idx
,
sc_strerror
(
rc
));
return
gpg_error
(
GPG_ERR_CARD
);
}
rc
=
ksba_cert_new
(
&
cert
);
if
(
rc
)
{
sc_pkcs15_free_certificate
(
certder
);
return
rc
;
}
rc
=
ksba_cert_init_from_mem
(
cert
,
certder
->
data
,
certder
->
data_len
);
sc_pkcs15_free_certificate
(
certder
);
if
(
rc
)
{
log_error
(
"failed to parse the certificate for private key %d: %s
\n
"
,
idx
,
gpg_strerror
(
rc
));
ksba_cert_release
(
cert
);
return
rc
;
}
if
(
card_help_get_keygrip
(
cert
,
keygrip
))
{
log_error
(
"failed to calculate the keygrip of private key %d
\n
"
,
idx
);
ksba_cert_release
(
cert
);
return
gpg_error
(
GPG_ERR_CARD
);
}
ksba_cert_release
(
cert
);
rc
=
0
;
return_keyid
:
if
(
keyid
)
{
char
*
p
;
int
i
;
*
keyid
=
p
=
xtrymalloc
(
9
+
pinfo
->
id
.
len
*
2
+
1
);
if
(
!*
keyid
)
return
out_of_core
();
p
=
stpcpy
(
p
,
"P15-5015."
);
for
(
i
=
0
;
i
<
pinfo
->
id
.
len
;
i
++
,
p
+=
2
)
sprintf
(
p
,
"%02X"
,
pinfo
->
id
.
value
[
i
]);
*
p
=
0
;
}
return
rc
;
}
/* See card.c for interface description */
static
int
p15_enum_certs
(
CARD
card
,
int
idx
,
char
**
certid
,
int
*
type
)
{
int
rc
;
struct
p15private_s
*
priv
;
struct
sc_pkcs15_object
*
obj
;
struct
sc_pkcs15_cert_info
*
cinfo
;
int
nobjs
;
rc
=
init_private_data
(
card
);
if
(
rc
)
return
rc
;
priv
=
card
->
p15priv
;
nobjs
=
priv
->
n_cert_objs
;
rc
=
0
;
if
(
idx
>=
nobjs
)
return
-1
;
obj
=
priv
->
cert_objs
[
idx
];
cinfo
=
obj
->
data
;
if
(
certid
)
{
char
*
p
;
int
i
;
*
certid
=
p
=
xtrymalloc
(
9
+
cinfo
->
id
.
len
*
2
+
1
);
if
(
!*
certid
)
return
out_of_core
();
p
=
stpcpy
(
p
,
"P15-5015."
);
for
(
i
=
0
;
i
<
cinfo
->
id
.
len
;
i
++
,
p
+=
2
)
sprintf
(
p
,
"%02X"
,
cinfo
->
id
.
value
[
i
]);
*
p
=
0
;
}
if
(
type
)
{
if
(
!
obj
->
df
)
*
type
=
0
;
/* unknown */
else
if
(
obj
->
df
->
type
==
SC_PKCS15_CDF
)
*
type
=
100
;
else
if
(
obj
->
df
->
type
==
SC_PKCS15_CDF_TRUSTED
)
*
type
=
101
;
else
if
(
obj
->
df
->
type
==
SC_PKCS15_CDF_USEFUL
)
*
type
=
102
;
else
*
type
=
0
;
/* error -> unknown */
}
return
rc
;
}
static
int
idstr_to_id
(
const
char
*
idstr
,
struct
sc_pkcs15_id
*
id
)
{
const
char
*
s
;
int
n
;
/* For now we only support the standard DF */
if
(
strncmp
(
idstr
,
"P15-5015."
,
9
)
)
return
gpg_error
(
GPG_ERR_INV_ID
);
for
(
s
=
idstr
+
9
,
n
=
0
;
hexdigitp
(
s
);
s
++
,
n
++
)
;
if
(
*
s
||
(
n
&
1
))
return
gpg_error
(
GPG_ERR_INV_ID
);
/*invalid or odd number of digits*/
n
/=
2
;
if
(
!
n
||
n
>
SC_PKCS15_MAX_ID_SIZE
)
return
gpg_error
(
GPG_ERR_INV_ID
);
/* empty or too large */
for
(
s
=
idstr
+
9
,
n
=
0
;
*
s
;
s
+=
2
,
n
++
)
id
->
value
[
n
]
=
xtoi_2
(
s
);
id
->
len
=
n
;
return
0
;
}
/* See card.c for interface description */
static
int
p15_read_cert
(
CARD
card
,
const
char
*
certidstr
,
unsigned
char
**
cert
,
size_t
*
ncert
)
{
struct
sc_pkcs15_object
*
tmpobj
;
struct
sc_pkcs15_id
certid
;
struct
sc_pkcs15_cert_info
*
certinfo
;
struct
sc_pkcs15_cert
*
certder
;
int
rc
;
if
(
!
card
||
!
certidstr
||
!
cert
||
!
ncert
)
return
gpg_error
(
GPG_ERR_INV_VALUE
);
if
(
!
card
->
p15card
)
return
gpg_error
(
GPG_ERR_NO_PKCS15_APP
);
rc
=
idstr_to_id
(
certidstr
,
&
certid
);
if
(
rc
)
return
rc
;
rc
=
sc_pkcs15_find_cert_by_id
(
card
->
p15card
,
&
certid
,
&
tmpobj
);
if
(
rc
)
{
log_info
(
"certificate '%s' not found: %s
\n
"
,
certidstr
,
sc_strerror
(
rc
));
return
-1
;
}
certinfo
=
tmpobj
->
data
;
rc
=
sc_pkcs15_read_certificate
(
card
->
p15card
,
certinfo
,
&
certder
);
if
(
rc
)
{
log_info
(
"failed to read certificate '%s': %s
\n
"
,
certidstr
,
sc_strerror
(
rc
));
return
gpg_error
(
GPG_ERR_CARD
);
}
*
cert
=
xtrymalloc
(
certder
->
data_len
);
if
(
!*
cert
)
{
gpg_error_t
tmperr
=
out_of_core
();
sc_pkcs15_free_certificate
(
certder
);
return
tmperr
;
}
memcpy
(
*
cert
,
certder
->
data
,
certder
->
data_len
);
*
ncert
=
certder
->
data_len
;
sc_pkcs15_free_certificate
(
certder
);
return
0
;
}
static
int
p15_prepare_key
(
CARD
card
,
const
char
*
keyidstr
,
int
(
pincb
)(
void
*
,
const
char
*
,
char
**
),
void
*
pincb_arg
,
struct
sc_pkcs15_object
**
r_keyobj
)
{
struct
sc_pkcs15_id
keyid
;
struct
sc_pkcs15_pin_info
*
pin
;
struct
sc_pkcs15_object
*
keyobj
,
*
pinobj
;
char
*
pinvalue
;
int
rc
;
rc
=
idstr_to_id
(
keyidstr
,
&
keyid
);
if
(
rc
)
return
rc
;
rc
=
sc_pkcs15_find_prkey_by_id
(
card
->
p15card
,
&
keyid
,
&
keyobj
);
if
(
rc
<
0
)
{
log_error
(
"private key not found: %s
\n
"
,
sc_strerror
(
rc
));
return
gpg_error
(
GPG_ERR_NO_SECKEY
);
}
rc
=
sc_pkcs15_find_pin_by_auth_id
(
card
->
p15card
,
&
keyobj
->
auth_id
,
&
pinobj
);
if
(
rc
)
{
log_error
(
"failed to find PIN by auth ID: %s
\n
"
,
sc_strerror
(
rc
));
return
gpg_error
(
GPG_ERR_BAD_PIN_METHOD
);
}
pin
=
pinobj
->
data
;
/* Fixme: pack this into a verification loop */
/* Fixme: we might want to pass pin->min_length and
pin->stored_length */
rc
=
pincb
(
pincb_arg
,
pinobj
->
label
,
&
pinvalue
);
if
(
rc
)
{
log_info
(
"PIN callback returned error: %s
\n
"
,
gpg_strerror
(
rc
));
return
rc
;
}
rc
=
sc_pkcs15_verify_pin
(
card
->
p15card
,
pin
,
pinvalue
,
strlen
(
pinvalue
));
xfree
(
pinvalue
);
if
(
rc
)
{
log_info
(
"PIN verification failed: %s
\n
"
,
sc_strerror
(
rc
));
return
gpg_error
(
GPG_ERR_BAD_PIN
);
}
/* fixme: check wheter we need to release KEYOBJ in case of an error */
*
r_keyobj
=
keyobj
;
return
0
;
}
/* See card.c for interface description */
static
int
p15_sign
(
CARD
card
,
const
char
*
keyidstr
,
int
hashalgo
,
int
(
pincb
)(
void
*
,
const
char
*
,
char
**
),
void
*
pincb_arg
,
const
void
*
indata
,
size_t
indatalen
,
unsigned
char
**
outdata
,
size_t
*
outdatalen
)
{
unsigned
int
cryptflags
;
struct
sc_pkcs15_object
*
keyobj
;
int
rc
;
unsigned
char
*
outbuf
=
NULL
;
size_t
outbuflen
;
if
(
hashalgo
!=
GCRY_MD_SHA1
)
return
gpg_error
(
GPG_ERR_UNSUPPORTED_ALGORITHM
);
rc
=
p15_prepare_key
(
card
,
keyidstr
,
pincb
,
pincb_arg
,
&
keyobj
);
if
(
rc
)
return
rc
;
cryptflags
=
SC_ALGORITHM_RSA_PAD_PKCS1
;
outbuflen
=
1024
;
outbuf
=
xtrymalloc
(
outbuflen
);
if
(
!
outbuf
)
return
out_of_core
();
rc
=
sc_pkcs15_compute_signature
(
card
->
p15card
,
keyobj
,
cryptflags
,
indata
,
indatalen
,
outbuf
,
outbuflen
);
if
(
rc
<
0
)
{
log_error
(
"failed to create signature: %s
\n
"
,
sc_strerror
(
rc
));
rc
=
gpg_error
(
GPG_ERR_CARD
);
}
else
{
*
outdatalen
=
rc
;
*
outdata
=
outbuf
;
outbuf
=
NULL
;
rc
=
0
;
}
xfree
(
outbuf
);
return
rc
;
}
/* See card.c for description */
static
int
p15_decipher
(
CARD
card
,
const
char
*
keyidstr
,
int
(
pincb
)(
void
*
,
const
char
*
,
char
**
),
void
*
pincb_arg
,
const
void
*
indata
,
size_t
indatalen
,
unsigned
char
**
outdata
,
size_t
*
outdatalen
)
{
struct
sc_pkcs15_object
*
keyobj
;
int
rc
;
unsigned
char
*
outbuf
=
NULL
;
size_t
outbuflen
;
rc
=
p15_prepare_key
(
card
,
keyidstr
,
pincb
,
pincb_arg
,
&
keyobj
);
if
(
rc
)
return
rc
;
if
(
card
&&
card
->
scard
&&
card
->
scard
->
driver
&&
!
strcasecmp
(
card
->
scard
->
driver
->
short_name
,
"tcos"
))
{
/* very ugly hack to force the use of a local key. We need this
until we have fixed the initialization code for TCOS cards */
struct
sc_pkcs15_prkey_info
*
prkey
=
keyobj
->
data
;
if
(
!
(
prkey
->
key_reference
&
0x80
))
{
prkey
->
key_reference
|=
0x80
;
log_debug
(
"using TCOS hack to force the use of local keys
\n
"
);
}
if
(
*
keyidstr
&&
keyidstr
[
strlen
(
keyidstr
)
-1
]
==
'6'
)
{
prkey
->
key_reference
|=
1
;
log_debug
(
"warning: using even more TCOS hacks
\n
"
);
}
}
outbuflen
=
indatalen
<
256
?
256
:
indatalen
;
outbuf
=
xtrymalloc
(
outbuflen
);
if
(
!
outbuf
)
return
out_of_core
();
rc
=
sc_pkcs15_decipher
(
card
->
p15card
,
keyobj
,
0
,
indata
,
indatalen
,
outbuf
,
outbuflen
);
if
(
rc
<
0
)
{
log_error
(
"failed to decipher the data: %s
\n
"
,
sc_strerror
(
rc
));
rc
=
gpg_error
(
GPG_ERR_CARD
);
}
else
{
*
outdatalen
=
rc
;
*
outdata
=
outbuf
;
outbuf
=
NULL
;
rc
=
0
;
}
xfree
(
outbuf
);
return
rc
;
}
/* Bind our operations to the card */
void
card_p15_bind
(
CARD
card
)
{
card
->
fnc
.
enum_keypairs
=
p15_enum_keypairs
;
card
->
fnc
.
enum_certs
=
p15_enum_certs
;
card
->
fnc
.
read_cert
=
p15_read_cert
;
card
->
fnc
.
sign
=
p15_sign
;
card
->
fnc
.
decipher
=
p15_decipher
;
}
#endif
/*HAVE_OPENSC*/
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Fri, Dec 5, 5:29 AM (7 h, 40 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
8d/73/cee8722f6753416eb69907879eb5
Attached To
rG GnuPG
Event Timeline
Log In to Comment