From bbb720034aa6422a7be4637e841db8588f4d0305 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Tue, 5 Sep 2000 22:30:38 +0000 Subject: [PATCH] Fix typo in rsautl. Add support for settable verify time in X509_verify_cert(). Document rsautl utility. --- CHANGES | 86 ++++++++++---------- apps/rsautl.c | 2 +- crypto/x509/x509.h | 2 + crypto/x509/x509_vfy.c | 37 +++++++-- crypto/x509/x509_vfy.h | 2 + doc/apps/rsautl.pod | 181 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 262 insertions(+), 48 deletions(-) create mode 100644 doc/apps/rsautl.pod diff --git a/CHANGES b/CHANGES index 4fe8ae9f71..3f0fa4ce86 100644 --- a/CHANGES +++ b/CHANGES @@ -3,57 +3,61 @@ _______________ Changes between 0.9.5a and 0.9.6 [xx XXX 2000] + + *) Allow the verify time to be set by an application, + rather than always using the current time. + [Steve Henson] - *) 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. + *) 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. + Lot of changes were necessary in order to support this + without completely rewriting the lookup code. - Authority and subject key identifier are now cached. + 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 - use only) have changed to handle the new X509_STORE - structure. This will break anything that messed round - with X509_STORE internally. + 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. - The functions X509_STORE_add_cert() now checks for an - exact match, rather than just subject name. + The functions X509_STORE_add_cert() now checks for an + exact match, rather than just subject name. - The X509_STORE API doesn't directly support the retrieval - 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_STORE API doesn't directly support the retrieval + 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 X509_VERIFY_CTX structure has been enhanced considerably. - 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(). + 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. + 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] + 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 excludes S/MIME capabilities. diff --git a/apps/rsautl.c b/apps/rsautl.c index 3a58b45800..f8f68d9422 100644 --- a/apps/rsautl.c +++ b/apps/rsautl.c @@ -141,7 +141,7 @@ int MAIN(int argc, char **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"); goto end; } diff --git a/crypto/x509/x509.h b/crypto/x509/x509.h index db80eda8e0..b95a2eec0b 100644 --- a/crypto/x509/x509.h +++ b/crypto/x509/x509.h @@ -800,7 +800,9 @@ RSA *RSAPrivateKey_dup(RSA *rsa); #endif /* !SSLEAY_MACROS */ +int X509_cmp_time(ASN1_TIME *s, time_t *t); 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); const char * X509_get_default_cert_area(void ); diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 07a8bd44b6..b8fb24a1d6 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -429,6 +429,7 @@ static int internal_verify(X509_STORE_CTX *ctx) int i,ok=0,n; X509 *xs,*xi; EVP_PKEY *pkey=NULL; + time_t *ptime; int (*cb)(); cb=ctx->verify_cb; @@ -438,8 +439,9 @@ static int internal_verify(X509_STORE_CTX *ctx) ctx->error_depth=n-1; n--; xi=sk_X509_value(ctx->chain,n); - if (X509_NAME_cmp(X509_get_subject_name(xi), - X509_get_issuer_name(xi)) == 0) + if(ctx->flags & X509_V_FLAG_USE_CHECK_TIME) ptime = &ctx->check_time; + else ptime = NULL; + if (ctx->check_issued(ctx, xi, xi)) xs=xi; else { @@ -485,7 +487,7 @@ static int internal_verify(X509_STORE_CTX *ctx) EVP_PKEY_free(pkey); pkey=NULL; - i=X509_cmp_current_time(X509_get_notBefore(xs)); + i=X509_cmp_time(X509_get_notBefore(xs), ptime); if (i == 0) { 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; } - i=X509_cmp_current_time(X509_get_notAfter(xs)); + i=X509_cmp_time(X509_get_notAfter(xs), ptime); if (i == 0) { ctx->error=X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD; @@ -540,6 +542,11 @@ end: } 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; ASN1_TIME atm; @@ -594,7 +601,7 @@ int X509_cmp_current_time(ASN1_TIME *ctm) atm.length=sizeof(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) { @@ -614,10 +621,17 @@ int X509_cmp_current_time(ASN1_TIME *ctm) } 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); + if(in_tm) t = *in_tm; + else time(&t); + t+=adj; if(!s) return ASN1_TIME_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)); } +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_ASN1_SET_OF(X509) diff --git a/crypto/x509/x509_vfy.h b/crypto/x509/x509_vfy.h index 71d56bb6dc..ba8cac51be 100644 --- a/crypto/x509/x509_vfy.h +++ b/crypto/x509/x509_vfy.h @@ -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_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose, 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 } diff --git a/doc/apps/rsautl.pod b/doc/apps/rsautl.pod new file mode 100644 index 0000000000..6a2466a386 --- /dev/null +++ b/doc/apps/rsautl.pod @@ -0,0 +1,181 @@ +=pod + +=head1 NAME + +rsautl - RSA utility + +=head1 SYNOPSIS + +B B +[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 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 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. Consider the self signed +example in certs/pca-cert.pem . Running B 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, L, L -- 2.34.1