/* * Copyright (c) 2001-2002 Packet Design, LLC. * All rights reserved. * * Subject to the following obligations and disclaimer of warranty, * use and redistribution of this software, in source or object code * forms, with or without modifications are expressly permitted by * Packet Design; provided, however, that: * * (i) Any and all reproductions of the source or object code * must include the copyright notice above and the following * disclaimer of warranties; and * (ii) No rights are granted, in any manner or form, to use * Packet Design trademarks, including the mark "PACKET DESIGN" * on advertising, endorsements, or otherwise except as such * appears in the above copyright notice or in the software. * * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE, * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 PACKET DESIGN IS ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Author: Archie Cobbs */ #include #include #include #include #include #include #include #include #include #include #include #include "structs/structs.h" #include "structs/type/array.h" #include "util/rsa_util.h" #include "util/typed_mem.h" static int rsa_util_verify_rsa(RSA *rsa, const u_char *md5, const u_char *sig, size_t siglen); /* * Create an RSA signature given an RSA private key filename. * * We assume the thing to be signed is an MD5 hash. * * Returns the signature length, or -1 if error. */ int rsa_util_sign(const char *privkeyfile, const u_char *md5, u_char *sig, size_t siglen) { u_char *vbuf = NULL; /* encrypted signature (md5) */ FILE *fp = NULL; RSA *rsa = NULL; int rtn = -1; int vlen; /* Open file */ if ((fp = fopen(privkeyfile, "r")) == NULL) { fprintf(stderr, "%s: %s\n", privkeyfile, strerror(errno)); goto done; } /* Read private key */ if ((rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL)) == NULL) { ERR_print_errors_fp(stderr); goto done; } /* Check buffer length */ if (siglen < RSA_size(rsa)) { errno = EINVAL; goto done; } /* Encrypt using private key */ if ((vlen = RSA_private_encrypt(MD5_DIGEST_LENGTH, (u_char *)md5, sig, rsa, RSA_PKCS1_PADDING)) <= 0) { ERR_print_errors_fp(stderr); goto done; } /* OK */ rtn = vlen; done: /* Clean up */ FREE(TYPED_MEM_TEMP, vbuf); RSA_free(rsa); if (fp != NULL) fclose(fp); /* Return result */ return (rtn); } /* * Verify an RSA signature given a public key filename. * * We assume the signature is a signature of an MD5 hash, and therefore * the input to the signature had length MD5_DIGEST_LENGTH. */ int rsa_util_verify(const char *pubkeyfile, const u_char *md5, const u_char *sig, size_t siglen) { EVP_PKEY *pkey = NULL; RSA *rsa = NULL; BIO *bio = NULL; int match = 0; /* Read in public key */ if ((bio = BIO_new(BIO_s_file())) == NULL) { ERR_print_errors_fp(stderr); goto done; } if (BIO_read_filename(bio, pubkeyfile) <= 0) goto done; if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) { ERR_print_errors_fp(stderr); goto done; } /* Get RSA public key */ if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) { ERR_print_errors_fp(stderr); goto done; } /* Verify */ match = rsa_util_verify_rsa(rsa, md5, sig, siglen); done: /* Clean up */ RSA_free(rsa); EVP_PKEY_free(pkey); BIO_free(bio); /* Return result */ return (match); } /* * Verify an RSA signature given a private key filename. * * We assume the signature is a signature of an MD5 hash, and therefore * the input to the signature had length MD5_DIGEST_LENGTH. */ int rsa_util_verify_priv(const char *privkeyfile, const u_char *md5, const u_char *sig, size_t siglen) { FILE *fp = NULL; RSA *rsa = NULL; int match = 0; /* Open file */ if ((fp = fopen(privkeyfile, "r")) == NULL) { fprintf(stderr, "%s: %s\n", privkeyfile, strerror(errno)); goto done; } /* Read private key */ if ((rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL)) == NULL) { ERR_print_errors_fp(stderr); goto done; } ERR_clear_error(); /* Verify */ match = rsa_util_verify_rsa(rsa, md5, sig, siglen); done: /* Clean up */ RSA_free(rsa); if (fp != NULL) fclose(fp); /* Return result */ return (match); } /* * Verify an RSA signature given an RSA public key. * * We assume the signature is a signature of an MD5 hash, and therefore * the input to the signature had length MD5_DIGEST_LENGTH. */ static int rsa_util_verify_rsa(RSA *rsa, const u_char *md5, const u_char *sig, size_t siglen) { u_char *vbuf = NULL; /* decrypted signature */ int match = 0; int vlen; /* Decrypt using public key */ if ((vbuf = MALLOC(TYPED_MEM_TEMP, MAX(siglen, RSA_size(rsa)))) == NULL) goto done; if ((vlen = RSA_public_decrypt(siglen, (u_char *)sig, vbuf, rsa, RSA_PKCS1_PADDING)) <= 0) { ERR_clear_error(); goto done; } /* Compare decrypted signature with original hash value */ if (vlen == MD5_DIGEST_LENGTH && memcmp(md5, vbuf, MD5_DIGEST_LENGTH) == 0) match = 1; done: /* Clean up */ FREE(TYPED_MEM_TEMP, vbuf); /* Return result */ return (match); }