From bd08a2bd0c1078e396c02a1ba11205a0d0a3a2a7 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Sun, 3 Sep 2000 23:13:48 +0000 Subject: [PATCH] Add 'rsautl' low level RSA utility. Add DER public key routines. Add -passin argument to 'ca' utility. Document sign and verify options to dgst. --- CHANGES | 5 + apps/Makefile.ssl | 6 +- apps/apps.c | 41 +++++++ apps/apps.h | 1 + apps/ca.c | 12 +- apps/progs.h | 4 + apps/progs.pl | 2 +- apps/rsautl.c | 276 ++++++++++++++++++++++++++++++++++++++++++++ crypto/x509/x509.h | 4 + crypto/x509/x_all.c | 22 ++++ doc/apps/ca.pod | 5 + doc/apps/dgst.pod | 63 +++++++++- 12 files changed, 432 insertions(+), 9 deletions(-) create mode 100644 apps/rsautl.c diff --git a/CHANGES b/CHANGES index dde9f64a99..424a25c1e8 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,11 @@ Changes between 0.9.5a and 0.9.6 [xx XXX 2000] + *) New openssl application 'rsautl'. This utility can be + used for low level RSA operations. DER public key + BIO/fp routines also added. + [Steve Henson] + *) New Configure entry and patches for compiling on QNX 4. [Andreas Schneider ] diff --git a/apps/Makefile.ssl b/apps/Makefile.ssl index 7681d24b29..85fae40e77 100644 --- a/apps/Makefile.ssl +++ b/apps/Makefile.ssl @@ -35,7 +35,7 @@ SCRIPTS=CA.sh CA.pl der_chop EXE= $(PROGRAM) E_EXE= verify asn1pars req dgst dh dhparam enc passwd gendh errstr \ - ca crl rsa dsa dsaparam \ + ca crl rsa rsautl dsa dsaparam \ x509 genrsa gendsa s_server s_client speed \ s_time version pkcs7 crl2pkcs7 sess_id ciphers nseq pkcs12 \ pkcs8 spkac smime rand @@ -51,14 +51,14 @@ RAND_SRC=app_rand.c E_OBJ= verify.o asn1pars.o req.o dgst.o dh.o dhparam.o enc.o passwd.o gendh.o errstr.o \ ca.o pkcs7.o crl2p7.o crl.o \ - rsa.o dsa.o dsaparam.o \ + rsa.o rsautl.o dsa.o dsaparam.o \ x509.o genrsa.o gendsa.o s_server.o s_client.o speed.o \ s_time.o $(A_OBJ) $(S_OBJ) $(RAND_OBJ) version.o sess_id.o \ ciphers.o nseq.o pkcs12.o pkcs8.o spkac.o smime.o rand.o E_SRC= verify.c asn1pars.c req.c dgst.c dh.c enc.c passwd.c gendh.c errstr.c ca.c \ pkcs7.c crl2p7.c crl.c \ - rsa.c dsa.c dsaparam.c \ + rsa.c rsautl.c dsa.c dsaparam.c \ x509.c genrsa.c gendsa.c s_server.c s_client.c speed.c \ s_time.c $(A_SRC) $(S_SRC) $(RAND_SRC) version.c sess_id.c \ ciphers.c nseq.c pkcs12.c pkcs8.c spkac.c smime.c rand.c diff --git a/apps/apps.c b/apps/apps.c index 7ae7c77ca6..e5a42d4d97 100644 --- a/apps/apps.c +++ b/apps/apps.c @@ -592,6 +592,47 @@ EVP_PKEY *load_key(BIO *err, char *file, int format, char *pass) return(pkey); } +EVP_PKEY *load_pubkey(BIO *err, char *file, int format) + { + BIO *key=NULL; + EVP_PKEY *pkey=NULL; + + if (file == NULL) + { + BIO_printf(err,"no keyfile specified\n"); + goto end; + } + key=BIO_new(BIO_s_file()); + if (key == NULL) + { + ERR_print_errors(err); + goto end; + } + if (BIO_read_filename(key,file) <= 0) + { + perror(file); + goto end; + } + if (format == FORMAT_ASN1) + { + pkey=d2i_PUBKEY_bio(key, NULL); + } + else if (format == FORMAT_PEM) + { + pkey=PEM_read_bio_PUBKEY(key,NULL,NULL,NULL); + } + else + { + BIO_printf(err,"bad input format specified for key\n"); + goto end; + } + end: + if (key != NULL) BIO_free(key); + if (pkey == NULL) + BIO_printf(err,"unable to load Public Key\n"); + return(pkey); + } + STACK_OF(X509) *load_certs(BIO *err, char *file, int format) { BIO *certs; diff --git a/apps/apps.h b/apps/apps.h index c44b21457a..151a94e919 100644 --- a/apps/apps.h +++ b/apps/apps.h @@ -152,6 +152,7 @@ int app_passwd(BIO *err, char *arg1, char *arg2, char **pass1, char **pass2); int add_oid_section(BIO *err, LHASH *conf); X509 *load_cert(BIO *err, char *file, int format); EVP_PKEY *load_key(BIO *err, char *file, int format, char *pass); +EVP_PKEY *load_pubkey(BIO *err, char *file, int format); STACK_OF(X509) *load_certs(BIO *err, char *file, int format); #define FORMAT_UNDEF 0 diff --git a/apps/ca.c b/apps/ca.c index d28cde99d8..0931401992 100644 --- a/apps/ca.c +++ b/apps/ca.c @@ -216,7 +216,7 @@ int MAIN(int, char **); int MAIN(int argc, char **argv) { - char *key=NULL; + char *key=NULL,*passargin=NULL; int total=0; int total_done=0; int badops=0; @@ -333,6 +333,11 @@ EF_ALIGNMENT=0; if (--argc < 1) goto bad; keyfile= *(++argv); } + else if (strcmp(*argv,"-passin") == 0) + { + if (--argc < 1) goto bad; + passargin= *(++argv); + } else if (strcmp(*argv,"-key") == 0) { if (--argc < 1) goto bad; @@ -526,6 +531,11 @@ bad: lookup_fail(section,ENV_PRIVATE_KEY); goto err; } + if(!key && !app_passwd(bio_err, passargin, NULL, &key, NULL)) + { + BIO_printf(bio_err,"Error getting password\n"); + goto err; + } if (BIO_read_filename(in,keyfile) <= 0) { perror(keyfile); diff --git a/apps/progs.h b/apps/progs.h index 66fe42e1e9..fbc65de632 100644 --- a/apps/progs.h +++ b/apps/progs.h @@ -14,6 +14,7 @@ extern int errstr_main(int argc,char *argv[]); extern int ca_main(int argc,char *argv[]); extern int crl_main(int argc,char *argv[]); extern int rsa_main(int argc,char *argv[]); +extern int rsautl_main(int argc,char *argv[]); extern int dsa_main(int argc,char *argv[]); extern int dsaparam_main(int argc,char *argv[]); extern int x509_main(int argc,char *argv[]); @@ -67,6 +68,9 @@ FUNCTION functions[] = { #ifndef NO_RSA {FUNC_TYPE_GENERAL,"rsa",rsa_main}, #endif +#ifndef NO_RSA + {FUNC_TYPE_GENERAL,"rsautl",rsautl_main}, +#endif #ifndef NO_DSA {FUNC_TYPE_GENERAL,"dsa",dsa_main}, #endif diff --git a/apps/progs.pl b/apps/progs.pl index 3d5e8de221..214025cd2d 100644 --- a/apps/progs.pl +++ b/apps/progs.pl @@ -29,7 +29,7 @@ foreach (@ARGV) $str="\t{FUNC_TYPE_GENERAL,\"$_\",${_}_main},\n"; if (($_ =~ /^s_/) || ($_ =~ /^ciphers$/)) { print "#if !defined(NO_SOCK) && !(defined(NO_SSL2) && defined(NO_SSL3))\n${str}#endif\n"; } - elsif ( ($_ =~ /^rsa$/) || ($_ =~ /^genrsa$/) ) + elsif ( ($_ =~ /^rsa$/) || ($_ =~ /^genrsa$/) || ($_ =~ /^rsautl$/)) { print "#ifndef NO_RSA\n${str}#endif\n"; } elsif ( ($_ =~ /^dsa$/) || ($_ =~ /^gendsa$/) || ($_ =~ /^dsaparam$/)) { print "#ifndef NO_DSA\n${str}#endif\n"; } diff --git a/apps/rsautl.c b/apps/rsautl.c new file mode 100644 index 0000000000..3a58b45800 --- /dev/null +++ b/apps/rsautl.c @@ -0,0 +1,276 @@ +/* rsautl.c */ +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL + * project 2000. + */ +/* ==================================================================== + * Copyright (c) 2000 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +#include "apps.h" +#include +#include + +#define RSA_SIGN 1 +#define RSA_VERIFY 2 +#define RSA_ENCRYPT 3 +#define RSA_DECRYPT 4 + +#define KEY_PRIVKEY 1 +#define KEY_PUBKEY 2 +#define KEY_CERT 3 + +static void usage(void); + +#undef PROG + +#define PROG rsautl_main + +int MAIN(int argc, char **); + +int MAIN(int argc, char **argv) +{ + BIO *in = NULL, *out = NULL; + char *infile = NULL, *outfile = NULL; + char *keyfile = NULL; + char rsa_mode = RSA_VERIFY, key_type = KEY_PRIVKEY; + int keyform = FORMAT_PEM; + char need_priv = 0, badarg = 0, rev = 0; + char hexdump = 0, asn1parse = 0; + X509 *x; + EVP_PKEY *pkey = NULL; + RSA *rsa = NULL; + unsigned char *rsa_in = NULL, *rsa_out = NULL, pad; + int rsa_inlen, rsa_outlen = 0; + int keysize; + + int ret = 1; + + argc--; + argv++; + + if(!bio_err) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); + pad = RSA_PKCS1_PADDING; + + while(argc >= 1) + { + if (!strcmp(*argv,"-in")) { + if (--argc < 1) badarg = 1; + infile= *(++argv); + } else if (!strcmp(*argv,"-out")) { + if (--argc < 1) badarg = 1; + outfile= *(++argv); + } else if(!strcmp(*argv, "-inkey")) { + if (--argc < 1) badarg = 1; + keyfile = *(++argv); + } else if(!strcmp(*argv, "-pubin")) { + key_type = KEY_PUBKEY; + } else if(!strcmp(*argv, "-certin")) { + key_type = KEY_CERT; + } + else if(!strcmp(*argv, "-asn1parse")) asn1parse = 1; + else if(!strcmp(*argv, "-hexdump")) hexdump = 1; + else if(!strcmp(*argv, "-raw")) pad = RSA_NO_PADDING; + else if(!strcmp(*argv, "-ssl")) pad = RSA_SSLV23_PADDING; + else if(!strcmp(*argv, "-pkcs")) pad = RSA_PKCS1_PADDING; + else if(!strcmp(*argv, "-sign")) { + rsa_mode = RSA_SIGN; + need_priv = 1; + } else if(!strcmp(*argv, "-verify")) rsa_mode = RSA_VERIFY; + else if(!strcmp(*argv, "-rev")) rev = 1; + else if(!strcmp(*argv, "-encrypt")) rsa_mode = RSA_ENCRYPT; + else if(!strcmp(*argv, "-decrypt")) { + rsa_mode = RSA_DECRYPT; + need_priv = 1; + } else badarg = 1; + if(badarg) { + usage(); + goto end; + } + argc--; + argv++; + } + + if(need_priv && (key_type == KEY_PRIVKEY)) { + BIO_printf(bio_err, "A private key is needed for this operation\n"); + goto end; + } + + switch(key_type) { + case KEY_PRIVKEY: + pkey = load_key(bio_err, keyfile, keyform, NULL); + break; + + case KEY_PUBKEY: + pkey = load_pubkey(bio_err, keyfile, keyform); + break; + + case KEY_CERT: + x = load_cert(bio_err, keyfile, keyform); + if(x) { + pkey = X509_get_pubkey(x); + X509_free(x); + } + break; + } + + if(!pkey) { + BIO_printf(bio_err, "Error loading key\n"); + return 1; + } + + rsa = EVP_PKEY_get1_RSA(pkey); + EVP_PKEY_free(pkey); + + if(!rsa) { + BIO_printf(bio_err, "Error getting RSA key\n"); + ERR_print_errors(bio_err); + goto end; + } + + + if(infile) { + if(!(in = BIO_new_file(infile, "rb"))) { + BIO_printf(bio_err, "Error Reading Input File\n"); + ERR_print_errors(bio_err); + goto end; + } + } else in = BIO_new_fp(stdin, BIO_NOCLOSE); + + if(outfile) { + if(!(out = BIO_new_file(outfile, "wb"))) { + BIO_printf(bio_err, "Error Reading Output File\n"); + ERR_print_errors(bio_err); + goto end; + } + } else out = BIO_new_fp(stdout, BIO_NOCLOSE); + + keysize = RSA_size(rsa); + + rsa_in = OPENSSL_malloc(keysize * 2); + rsa_out = OPENSSL_malloc(keysize); + + /* Read the input data */ + rsa_inlen = BIO_read(in, rsa_in, keysize * 2); + if(rsa_inlen <= 0) { + BIO_printf(bio_err, "Error reading input Data\n"); + exit(1); + } + if(rev) { + int i; + unsigned char ctmp; + for(i = 0; i < rsa_inlen/2; i++) { + ctmp = rsa_in[i]; + rsa_in[i] = rsa_in[rsa_inlen - 1 - i]; + rsa_in[rsa_inlen - 1 - i] = ctmp; + } + } + switch(rsa_mode) { + + case RSA_VERIFY: + rsa_outlen = RSA_public_decrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad); + break; + + case RSA_SIGN: + rsa_outlen = RSA_private_encrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad); + break; + + case RSA_ENCRYPT: + rsa_outlen = RSA_public_encrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad); + break; + + case RSA_DECRYPT: + rsa_outlen = RSA_private_decrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad); + break; + + } + + if(rsa_outlen <= 0) { + BIO_printf(bio_err, "RSA operation error\n"); + ERR_print_errors(bio_err); + goto end; + } + ret = 0; + if(asn1parse) { + if(!ASN1_parse_dump(out, rsa_out, rsa_outlen, 1, -1)) { + ERR_print_errors(bio_err); + } + } else if(hexdump) BIO_dump(out, (char *)rsa_out, rsa_outlen); + else BIO_write(out, rsa_out, rsa_outlen); + end: + RSA_free(rsa); + BIO_free(in); + BIO_free(out); + if(rsa_in) OPENSSL_free(rsa_in); + if(rsa_out) OPENSSL_free(rsa_out); + return ret; +} + +static void usage() +{ + BIO_printf(bio_err, "Usage: rsautl [options]\n"); + BIO_printf(bio_err, "-in file input file\n"); + BIO_printf(bio_err, "-out file output file\n"); + BIO_printf(bio_err, "-inkey file input key\n"); + BIO_printf(bio_err, "-pubin input is an RSA public\n"); + BIO_printf(bio_err, "-certin input is a certificate carrying an RSA public key\n"); + BIO_printf(bio_err, "-ssl use SSL v2 padding\n"); + BIO_printf(bio_err, "-raw use no padding\n"); + BIO_printf(bio_err, "-pkcs use PKCS#1 padding (default)\n"); + BIO_printf(bio_err, "-sign sign with private key\n"); + BIO_printf(bio_err, "-verify verify with public key\n"); + BIO_printf(bio_err, "-encrypt encrypt with public key\n"); + BIO_printf(bio_err, "-decrypt decrypt with private key\n"); + BIO_printf(bio_err, "-hexdump hex dump output\n"); +} + diff --git a/crypto/x509/x509.h b/crypto/x509/x509.h index ffa6e01251..7808b6a112 100644 --- a/crypto/x509/x509.h +++ b/crypto/x509/x509.h @@ -744,6 +744,8 @@ int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp,PKCS8_PRIV_KEY_INFO *p8inf); int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key); int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey); EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a); +int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey); +EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a); #endif #ifndef NO_BIO @@ -775,6 +777,8 @@ int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp,PKCS8_PRIV_KEY_INFO *p8inf); int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key); int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey); EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a); +int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey); +EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a); #endif X509 *X509_dup(X509 *x509); diff --git a/crypto/x509/x_all.c b/crypto/x509/x_all.c index dd5796e205..9bd6e2a39b 100644 --- a/crypto/x509/x_all.c +++ b/crypto/x509/x_all.c @@ -504,6 +504,17 @@ EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a) (char *(*)())d2i_AutoPrivateKey, (fp),(unsigned char **)(a))); } +int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey) + { + return(ASN1_i2d_fp(i2d_PUBKEY,fp,(unsigned char *)pkey)); + } + +EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a) +{ + return((EVP_PKEY *)ASN1_d2i_fp((char *(*)())EVP_PKEY_new, + (char *(*)())d2i_PUBKEY, (fp),(unsigned char **)(a))); +} + #endif PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, @@ -541,3 +552,14 @@ EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a) return((EVP_PKEY *)ASN1_d2i_bio((char *(*)())EVP_PKEY_new, (char *(*)())d2i_AutoPrivateKey, (bp),(unsigned char **)(a))); } + +int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey) + { + return(ASN1_i2d_bio(i2d_PUBKEY,bp,(unsigned char *)pkey)); + } + +EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a) + { + return((EVP_PKEY *)ASN1_d2i_bio((char *(*)())EVP_PKEY_new, + (char *(*)())d2i_PUBKEY, (bp),(unsigned char **)(a))); + } diff --git a/doc/apps/ca.pod b/doc/apps/ca.pod index efe1b3c230..d352925864 100644 --- a/doc/apps/ca.pod +++ b/doc/apps/ca.pod @@ -23,6 +23,7 @@ B B [B<-policy arg>] [B<-keyfile arg>] [B<-key arg>] +[B<-passin arg>] [B<-cert file>] [B<-in file>] [B<-out file>] @@ -99,6 +100,10 @@ the password used to encrypt the private key. Since on some systems the command line arguments are visible (e.g. Unix with the 'ps' utility) this option should be used with caution. +=item B<-passin arg> + +the key password source. For more information about the format of B +see the B section in L. =item B<-verbose> this prints extra details about the operations being performed. diff --git a/doc/apps/dgst.pod b/doc/apps/dgst.pod index fcfd3ecf23..6fbf4339ab 100644 --- a/doc/apps/dgst.pod +++ b/doc/apps/dgst.pod @@ -7,9 +7,16 @@ dgst, md5, md2, sha1, sha, mdc2, ripemd160 - message digests =head1 SYNOPSIS B B -[B<-md5|-md2|-sha1|-sha|mdc2|-ripemd160>] +[B<-md5|-md2|-sha1|-sha|-mdc2|-ripemd160|-dss1>] [B<-c>] [B<-d>] +[B<-hex>] +[B<-binary>] +[B<-out filename>] +[B<-sign filename>] +[B<-verify filename>] +[B<-prverify filename>] +[B<-signature filename>] [B] [B] @@ -19,8 +26,8 @@ B B =head1 DESCRIPTION -The digest functions print out the message digest of a supplied file or files -in hexadecimal form. +The digest functions output the message digest of a supplied file or files +in hexadecimal form. They can also be used for digital signing and verification. =head1 OPTIONS @@ -28,12 +35,51 @@ in hexadecimal form. =item B<-c> -print out the digest in two digit groups separated by colons. +print out the digest in two digit groups separated by colons, only relevant if +B format output is used. =item B<-d> print out BIO debugging information. +=item B<-hex> + +digest is to be output as a hex dump. This is the default case for a "normal" +digest as opposed to a digital signature. + +=item B<-binary> + +output the digest or signature in binary form. + +=item B<-out filename> + +filename to output to, or standard output by default. + +=item B<-sign filename> + +digitally sign the digest using the private key in "filename". + +=item B<-verify filename> + +verify the signature using the the public key in "filename". +The output is either "Verification OK" or "Verification Failure". + +=item B<-prverify filename> + +verify the signature using the the private key in "filename". + +=item B<-signature filename> + +the actual signature to verify. + +=item B<-rand file(s)> + +a file or files containing random data used to seed the random number +generator, or an EGD socket (see L). +Multiple files can be specified separated by a OS-dependent character. +The separator is B<;> for MS-Windows, B<,> for OpenVMS, and B<:> for +all others. + =item B file or files to digest. If no files are specified then standard input is @@ -46,4 +92,13 @@ used. The digest of choice for all new applications is SHA1. Other digests are however still widely used. +If you wish to sign or verify data using the DSA algorithm then the dss1 +digest must be used. + +A source of random numbers is required for certain signing algorithms, in +particular DSA. + +The signing and verify options should only be used if a single file is +being signed or verified. + =cut -- 2.25.1