Fix typo in rsautl.
Add support for settable verify time in X509_verify_cert(). Document rsautl utility.
This commit is contained in:
parent
4af6e2432b
commit
bbb720034a
92
CHANGES
92
CHANGES
@ -3,57 +3,61 @@
|
|||||||
_______________
|
_______________
|
||||||
|
|
||||||
Changes between 0.9.5a and 0.9.6 [xx XXX 2000]
|
Changes between 0.9.5a and 0.9.6 [xx XXX 2000]
|
||||||
|
|
||||||
*) Phase 2 verify code reorganisation. The certificate
|
|
||||||
verify code now looks up an issuer certificate by a
|
|
||||||
number of criteria: subject name, authority key id
|
|
||||||
and key usage. It also verifies self signed certificates
|
|
||||||
by the same criteria. The main comparison function is
|
|
||||||
X509_check_issued() which performs these checks.
|
|
||||||
|
|
||||||
Lot of changes were necessary in order to support this
|
|
||||||
without completely rewriting the lookup code.
|
|
||||||
|
|
||||||
Authority and subject key identifier are now cached.
|
|
||||||
|
|
||||||
The LHASH 'certs' is X509_STORE has now been replaced
|
|
||||||
by a STACK_OF(X509_OBJECT). This is mainly because an
|
|
||||||
LHASH can't store or retrieve multiple objects with
|
|
||||||
the same hash value.
|
|
||||||
|
|
||||||
As a result various functions (which were all internal
|
*) Allow the verify time to be set by an application,
|
||||||
use only) have changed to handle the new X509_STORE
|
rather than always using the current time.
|
||||||
structure. This will break anything that messed round
|
[Steve Henson]
|
||||||
with X509_STORE internally.
|
|
||||||
|
*) Phase 2 verify code reorganisation. The certificate
|
||||||
|
verify code now looks up an issuer certificate by a
|
||||||
|
number of criteria: subject name, authority key id
|
||||||
|
and key usage. It also verifies self signed certificates
|
||||||
|
by the same criteria. The main comparison function is
|
||||||
|
X509_check_issued() which performs these checks.
|
||||||
|
|
||||||
The functions X509_STORE_add_cert() now checks for an
|
Lot of changes were necessary in order to support this
|
||||||
exact match, rather than just subject name.
|
without completely rewriting the lookup code.
|
||||||
|
|
||||||
The X509_STORE API doesn't directly support the retrieval
|
Authority and subject key identifier are now cached.
|
||||||
of multiple certificates matching a given criteria, however
|
|
||||||
this can be worked round by performing a lookup first
|
|
||||||
(which will fill the cache with candidate certificates)
|
|
||||||
and then examining the cache for matches. This is probably
|
|
||||||
the best we can do without throwing out X509_LOOKUP
|
|
||||||
entirely (maybe later...).
|
|
||||||
|
|
||||||
The X509_VERIFY_CTX structure has been enhanced considerably.
|
The LHASH 'certs' is X509_STORE has now been replaced
|
||||||
|
by a STACK_OF(X509_OBJECT). This is mainly because an
|
||||||
|
LHASH can't store or retrieve multiple objects with
|
||||||
|
the same hash value.
|
||||||
|
|
||||||
|
As a result various functions (which were all internal
|
||||||
|
use only) have changed to handle the new X509_STORE
|
||||||
|
structure. This will break anything that messed round
|
||||||
|
with X509_STORE internally.
|
||||||
|
|
||||||
All certificate lookup operations now go via a get_issuer()
|
The functions X509_STORE_add_cert() now checks for an
|
||||||
callback. Although this currently uses an X509_STORE it
|
exact match, rather than just subject name.
|
||||||
can be replaced by custom lookups. This is a simple way
|
|
||||||
to bypass the X509_STORE hackery necessary to make this
|
|
||||||
work and makes it possible to use more efficient techniques
|
|
||||||
in future. A very simple version which uses a simple
|
|
||||||
STACK for its trusted certificate store is also provided
|
|
||||||
using X509_STORE_CTX_trusted_stack().
|
|
||||||
|
|
||||||
The verify_cb() and verify() callbacks now have equivalents
|
The X509_STORE API doesn't directly support the retrieval
|
||||||
in the X509_STORE_CTX structure.
|
of multiple certificates matching a given criteria, however
|
||||||
|
this can be worked round by performing a lookup first
|
||||||
|
(which will fill the cache with candidate certificates)
|
||||||
|
and then examining the cache for matches. This is probably
|
||||||
|
the best we can do without throwing out X509_LOOKUP
|
||||||
|
entirely (maybe later...).
|
||||||
|
|
||||||
X509_STORE_CTX also has a 'flags' field which can be used
|
The X509_VERIFY_CTX structure has been enhanced considerably.
|
||||||
to customise the verify behaviour.
|
|
||||||
[Steve Henson]
|
All certificate lookup operations now go via a get_issuer()
|
||||||
|
callback. Although this currently uses an X509_STORE it
|
||||||
|
can be replaced by custom lookups. This is a simple way
|
||||||
|
to bypass the X509_STORE hackery necessary to make this
|
||||||
|
work and makes it possible to use more efficient techniques
|
||||||
|
in future. A very simple version which uses a simple
|
||||||
|
STACK for its trusted certificate store is also provided
|
||||||
|
using X509_STORE_CTX_trusted_stack().
|
||||||
|
|
||||||
|
The verify_cb() and verify() callbacks now have equivalents
|
||||||
|
in the X509_STORE_CTX structure.
|
||||||
|
|
||||||
|
X509_STORE_CTX also has a 'flags' field which can be used
|
||||||
|
to customise the verify behaviour.
|
||||||
|
[Steve Henson]
|
||||||
|
|
||||||
*) Add new PKCS#7 signing option PKCS7_NOSMIMECAP which
|
*) Add new PKCS#7 signing option PKCS7_NOSMIMECAP which
|
||||||
excludes S/MIME capabilities.
|
excludes S/MIME capabilities.
|
||||||
|
@ -141,7 +141,7 @@ int MAIN(int argc, char **argv)
|
|||||||
argv++;
|
argv++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(need_priv && (key_type == KEY_PRIVKEY)) {
|
if(need_priv && (key_type != KEY_PRIVKEY)) {
|
||||||
BIO_printf(bio_err, "A private key is needed for this operation\n");
|
BIO_printf(bio_err, "A private key is needed for this operation\n");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
@ -800,7 +800,9 @@ RSA *RSAPrivateKey_dup(RSA *rsa);
|
|||||||
|
|
||||||
#endif /* !SSLEAY_MACROS */
|
#endif /* !SSLEAY_MACROS */
|
||||||
|
|
||||||
|
int X509_cmp_time(ASN1_TIME *s, time_t *t);
|
||||||
int X509_cmp_current_time(ASN1_TIME *s);
|
int X509_cmp_current_time(ASN1_TIME *s);
|
||||||
|
ASN1_TIME * X509_time_adj(ASN1_TIME *s, long adj, time_t *t);
|
||||||
ASN1_TIME * X509_gmtime_adj(ASN1_TIME *s, long adj);
|
ASN1_TIME * X509_gmtime_adj(ASN1_TIME *s, long adj);
|
||||||
|
|
||||||
const char * X509_get_default_cert_area(void );
|
const char * X509_get_default_cert_area(void );
|
||||||
|
@ -429,6 +429,7 @@ static int internal_verify(X509_STORE_CTX *ctx)
|
|||||||
int i,ok=0,n;
|
int i,ok=0,n;
|
||||||
X509 *xs,*xi;
|
X509 *xs,*xi;
|
||||||
EVP_PKEY *pkey=NULL;
|
EVP_PKEY *pkey=NULL;
|
||||||
|
time_t *ptime;
|
||||||
int (*cb)();
|
int (*cb)();
|
||||||
|
|
||||||
cb=ctx->verify_cb;
|
cb=ctx->verify_cb;
|
||||||
@ -438,8 +439,9 @@ static int internal_verify(X509_STORE_CTX *ctx)
|
|||||||
ctx->error_depth=n-1;
|
ctx->error_depth=n-1;
|
||||||
n--;
|
n--;
|
||||||
xi=sk_X509_value(ctx->chain,n);
|
xi=sk_X509_value(ctx->chain,n);
|
||||||
if (X509_NAME_cmp(X509_get_subject_name(xi),
|
if(ctx->flags & X509_V_FLAG_USE_CHECK_TIME) ptime = &ctx->check_time;
|
||||||
X509_get_issuer_name(xi)) == 0)
|
else ptime = NULL;
|
||||||
|
if (ctx->check_issued(ctx, xi, xi))
|
||||||
xs=xi;
|
xs=xi;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -485,7 +487,7 @@ static int internal_verify(X509_STORE_CTX *ctx)
|
|||||||
EVP_PKEY_free(pkey);
|
EVP_PKEY_free(pkey);
|
||||||
pkey=NULL;
|
pkey=NULL;
|
||||||
|
|
||||||
i=X509_cmp_current_time(X509_get_notBefore(xs));
|
i=X509_cmp_time(X509_get_notBefore(xs), ptime);
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
{
|
{
|
||||||
ctx->error=X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD;
|
ctx->error=X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD;
|
||||||
@ -503,7 +505,7 @@ static int internal_verify(X509_STORE_CTX *ctx)
|
|||||||
xs->valid=1;
|
xs->valid=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i=X509_cmp_current_time(X509_get_notAfter(xs));
|
i=X509_cmp_time(X509_get_notAfter(xs), ptime);
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
{
|
{
|
||||||
ctx->error=X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD;
|
ctx->error=X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD;
|
||||||
@ -540,6 +542,11 @@ end:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int X509_cmp_current_time(ASN1_TIME *ctm)
|
int X509_cmp_current_time(ASN1_TIME *ctm)
|
||||||
|
{
|
||||||
|
return X509_cmp_time(ctm, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int X509_cmp_time(ASN1_TIME *ctm, time_t *cmp_time)
|
||||||
{
|
{
|
||||||
char *str;
|
char *str;
|
||||||
ASN1_TIME atm;
|
ASN1_TIME atm;
|
||||||
@ -594,7 +601,7 @@ int X509_cmp_current_time(ASN1_TIME *ctm)
|
|||||||
atm.length=sizeof(buff2);
|
atm.length=sizeof(buff2);
|
||||||
atm.data=(unsigned char *)buff2;
|
atm.data=(unsigned char *)buff2;
|
||||||
|
|
||||||
X509_gmtime_adj(&atm,-offset*60);
|
X509_time_adj(&atm,-offset*60, cmp_time);
|
||||||
|
|
||||||
if(ctm->type == V_ASN1_UTCTIME)
|
if(ctm->type == V_ASN1_UTCTIME)
|
||||||
{
|
{
|
||||||
@ -614,10 +621,17 @@ int X509_cmp_current_time(ASN1_TIME *ctm)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ASN1_TIME *X509_gmtime_adj(ASN1_TIME *s, long adj)
|
ASN1_TIME *X509_gmtime_adj(ASN1_TIME *s, long adj)
|
||||||
|
{
|
||||||
|
return X509_time_adj(s, adj, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASN1_TIME *X509_time_adj(ASN1_TIME *s, long adj, time_t *in_tm)
|
||||||
{
|
{
|
||||||
time_t t;
|
time_t t;
|
||||||
|
|
||||||
time(&t);
|
if(in_tm) t = *in_tm;
|
||||||
|
else time(&t);
|
||||||
|
|
||||||
t+=adj;
|
t+=adj;
|
||||||
if(!s) return ASN1_TIME_set(s, t);
|
if(!s) return ASN1_TIME_set(s, t);
|
||||||
if(s->type == V_ASN1_UTCTIME) return(ASN1_UTCTIME_set(s,t));
|
if(s->type == V_ASN1_UTCTIME) return(ASN1_UTCTIME_set(s,t));
|
||||||
@ -855,6 +869,17 @@ void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx)
|
|||||||
memset(&ctx->ex_data,0,sizeof(CRYPTO_EX_DATA));
|
memset(&ctx->ex_data,0,sizeof(CRYPTO_EX_DATA));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, long flags)
|
||||||
|
{
|
||||||
|
ctx->flags |= flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, long flags, time_t t)
|
||||||
|
{
|
||||||
|
ctx->check_time = t;
|
||||||
|
ctx->flags |= X509_V_FLAG_USE_CHECK_TIME;
|
||||||
|
}
|
||||||
|
|
||||||
IMPLEMENT_STACK_OF(X509)
|
IMPLEMENT_STACK_OF(X509)
|
||||||
IMPLEMENT_ASN1_SET_OF(X509)
|
IMPLEMENT_ASN1_SET_OF(X509)
|
||||||
|
|
||||||
|
@ -380,6 +380,8 @@ int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose);
|
|||||||
int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust);
|
int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust);
|
||||||
int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose,
|
int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose,
|
||||||
int purpose, int trust);
|
int purpose, int trust);
|
||||||
|
void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, long flags);
|
||||||
|
void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, long flags, time_t t);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
181
doc/apps/rsautl.pod
Normal file
181
doc/apps/rsautl.pod
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
=pod
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
rsautl - RSA utility
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
B<openssl> B<rsautl>
|
||||||
|
[B<-in file>]
|
||||||
|
[B<-out file>]
|
||||||
|
[B<-inkey file>]
|
||||||
|
[B<-pubin>]
|
||||||
|
[B<-certin>]
|
||||||
|
[B<-sign>]
|
||||||
|
[B<-verify>]
|
||||||
|
[B<-encrypt>]
|
||||||
|
[B<-decrypt>]
|
||||||
|
[B<-pkcs>]
|
||||||
|
[B<-ssl>]
|
||||||
|
[B<-raw>]
|
||||||
|
[B<-hexdump>]
|
||||||
|
[B<-asn1parse>]
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
The B<rsautl> command can be used to sign, verify, encrypt and decrypt
|
||||||
|
data using the RSA algorithm.
|
||||||
|
|
||||||
|
=head1 COMMAND OPTIONS
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item B<-in filename>
|
||||||
|
|
||||||
|
This specifies the input filename to read data from or standard input
|
||||||
|
if this option is not specified.
|
||||||
|
|
||||||
|
=item B<-out filename>
|
||||||
|
|
||||||
|
specifies the output filename to write to or standard output by
|
||||||
|
default.
|
||||||
|
|
||||||
|
=item B<-inkey file>
|
||||||
|
|
||||||
|
the input key file, by default it should be an RSA private key.
|
||||||
|
|
||||||
|
=item B<-pubin>
|
||||||
|
|
||||||
|
the input file is an RSA public key.
|
||||||
|
|
||||||
|
=item B<-certin>
|
||||||
|
|
||||||
|
the input is a certificate containing an RSA public key.
|
||||||
|
|
||||||
|
=item B<-sign>
|
||||||
|
|
||||||
|
sign the input data and output the signed result. This requires
|
||||||
|
and RSA private key.
|
||||||
|
|
||||||
|
=item B<-verify>
|
||||||
|
|
||||||
|
verify the input data and output the recovered data.
|
||||||
|
|
||||||
|
=item B<-encrypt>
|
||||||
|
|
||||||
|
encrypt the input data using an RSA public key.
|
||||||
|
|
||||||
|
=item B<-decrypt>
|
||||||
|
|
||||||
|
decrypt the input data using an RSA private key.
|
||||||
|
|
||||||
|
=item B<-pkcs, -ssl, -raw>
|
||||||
|
|
||||||
|
the padding to use, PKCS#1 v1.5 (the default) SSL v2 or no padding
|
||||||
|
respectively.
|
||||||
|
|
||||||
|
=item B<-hexdump>
|
||||||
|
|
||||||
|
hex dump the output data.
|
||||||
|
|
||||||
|
=item B<-asn1parse>
|
||||||
|
|
||||||
|
asn1parse the output data, this is useful when combined with the
|
||||||
|
B<-verify> option.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 NOTES
|
||||||
|
|
||||||
|
B<rsautl> because it uses the RSA algorithm directly can only be
|
||||||
|
used to sign or verify small pieces of data.
|
||||||
|
|
||||||
|
=head1 EXAMPLES
|
||||||
|
|
||||||
|
Sign the some data using a private key:
|
||||||
|
|
||||||
|
openssl rsautl -sign -in file -inkey key.pem -out sig
|
||||||
|
|
||||||
|
Recover the signed data
|
||||||
|
|
||||||
|
openssl rsautl -sign -in sig -inkey key.pem
|
||||||
|
|
||||||
|
Examine the raw signed data:
|
||||||
|
|
||||||
|
openssl rsautl -sign -in file -inkey key.pem -raw -hexdump
|
||||||
|
|
||||||
|
0000 - 00 01 ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................
|
||||||
|
0010 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................
|
||||||
|
0020 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................
|
||||||
|
0030 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................
|
||||||
|
0040 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................
|
||||||
|
0050 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................
|
||||||
|
0060 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................
|
||||||
|
0070 - ff ff ff ff 00 68 65 6c-6c 6f 20 77 6f 72 6c 64 .....hello world
|
||||||
|
|
||||||
|
The PKCS#1 block formatting is evident from this. If this was done using
|
||||||
|
encrypt and decrypt the block would have been of type 2 (the second byte)
|
||||||
|
and random padding data visible instead of the 0xff bytes.
|
||||||
|
|
||||||
|
It is possible to analyse the signature of certificates using this
|
||||||
|
utility in conjunction with B<asn1parse>. Consider the self signed
|
||||||
|
example in certs/pca-cert.pem . Running B<asn1parse> as follows yields:
|
||||||
|
|
||||||
|
openssl asn1parse -in pca-cert.pem
|
||||||
|
|
||||||
|
0:d=0 hl=4 l= 742 cons: SEQUENCE
|
||||||
|
4:d=1 hl=4 l= 591 cons: SEQUENCE
|
||||||
|
8:d=2 hl=2 l= 3 cons: cont [ 0 ]
|
||||||
|
10:d=3 hl=2 l= 1 prim: INTEGER :02
|
||||||
|
13:d=2 hl=2 l= 1 prim: INTEGER :00
|
||||||
|
16:d=2 hl=2 l= 13 cons: SEQUENCE
|
||||||
|
18:d=3 hl=2 l= 9 prim: OBJECT :md5WithRSAEncryption
|
||||||
|
29:d=3 hl=2 l= 0 prim: NULL
|
||||||
|
31:d=2 hl=2 l= 92 cons: SEQUENCE
|
||||||
|
33:d=3 hl=2 l= 11 cons: SET
|
||||||
|
35:d=4 hl=2 l= 9 cons: SEQUENCE
|
||||||
|
37:d=5 hl=2 l= 3 prim: OBJECT :countryName
|
||||||
|
42:d=5 hl=2 l= 2 prim: PRINTABLESTRING :AU
|
||||||
|
....
|
||||||
|
599:d=1 hl=2 l= 13 cons: SEQUENCE
|
||||||
|
601:d=2 hl=2 l= 9 prim: OBJECT :md5WithRSAEncryption
|
||||||
|
612:d=2 hl=2 l= 0 prim: NULL
|
||||||
|
614:d=1 hl=3 l= 129 prim: BIT STRING
|
||||||
|
|
||||||
|
|
||||||
|
The final BIT STRING contains the actual signature. It can be extracted with:
|
||||||
|
|
||||||
|
openssl asn1parse -in pca-cert.pem -out sig -noout -strparse 614
|
||||||
|
|
||||||
|
The certificate public key can be extracted with:
|
||||||
|
|
||||||
|
openssl x509 -in test/testx509.pem -pubout -noout >pubkey.pem
|
||||||
|
|
||||||
|
The signature can be analysed with:
|
||||||
|
|
||||||
|
openssl rsautl -in sig -verify -asn1parse -inkey pubkey.pem -pubin
|
||||||
|
|
||||||
|
0:d=0 hl=2 l= 32 cons: SEQUENCE
|
||||||
|
2:d=1 hl=2 l= 12 cons: SEQUENCE
|
||||||
|
4:d=2 hl=2 l= 8 prim: OBJECT :md5
|
||||||
|
14:d=2 hl=2 l= 0 prim: NULL
|
||||||
|
16:d=1 hl=2 l= 16 prim: OCTET STRING
|
||||||
|
0000 - f3 46 9e aa 1a 4a 73 c9-37 ea 93 00 48 25 08 b5 .F...Js.7...H%..
|
||||||
|
|
||||||
|
This is the parsed version of an ASN1 DigestInfo structure. It can be seen that
|
||||||
|
the digest used was md5. The actual part of the certificate that was signed can
|
||||||
|
be extracted with:
|
||||||
|
|
||||||
|
openssl asn1parse -in pca-cert.pem -out tbs -noout -strparse 4
|
||||||
|
|
||||||
|
and its digest computed with:
|
||||||
|
|
||||||
|
openssl md5 -c tbs
|
||||||
|
MD5(tbs)= f3:46:9e:aa:1a:4a:73:c9:37:ea:93:00:48:25:08:b5
|
||||||
|
|
||||||
|
which it can be seen agrees with the recovered value above.
|
||||||
|
|
||||||
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
L<dgst(1)|dgst(1)>, L<rsa(1)|rsa(1)>, L<genrsa(1)|genrsa(1)>
|
Loading…
x
Reference in New Issue
Block a user