/* ** Copyright (c) 2005-2007 Sendmail, Inc. and its suppliers. ** All rights reserved. */ #ifndef lint static char dkim_test_c_id[] = "@(#)$Id: dkim-test.c,v 1.8 2007/12/03 07:43:25 msk Exp $"; #endif /* !lint */ /* system includes */ #include #include #include #include #include #include #include /* libsm includes */ #include /* openssl includes */ #include #include #include /* libdkim includes */ #include "dkim-types.h" #include "dkim-keys.h" #include "dkim-util.h" #include "dkim-test.h" #include "dkim.h" /* prototypes from elsewhere */ extern DKIM_STAT dkim_get_key __P((DKIM *, DKIM_SIGINFO *)); /* ** DKIM_TEST_KEY -- retrieve a public key and verify it against a provided ** private key ** ** Parameters: ** lib -- DKIM library handle ** selector -- selector ** domain -- domain name ** key -- private key to verify (PEM format) ** keylen -- size of private key ** err -- error buffer (may be NULL) ** errlen -- size of error buffer ** ** Return value: ** 1 -- keys don't match ** 0 -- keys match (or no key provided) ** -1 -- error */ int dkim_test_key(DKIM_LIB *lib, char *selector, char *domain, char *key, size_t keylen, char *err, size_t errlen) { int status = 0; DKIM_STAT stat; DKIM *dkim; DKIM_SIGINFO *sig; BIO *keybuf; BIO *outkey; void *ptr; struct dkim_rsa *rsa; assert(lib != NULL); assert(selector != NULL); assert(domain != NULL); dkim = dkim_verify(lib, "test", NULL, &stat); if (dkim == NULL) { if (err != NULL) sm_strlcpy(err, dkim_getresultstr(stat), errlen); return -1; } dkim->dkim_siglist = DKIM_MALLOC(dkim, sizeof(sig) * 2); if (dkim->dkim_siglist == NULL) { (void) dkim_free(dkim); if (err != NULL) { snprintf(err, errlen, "unable to allocate %d byte(s)", sizeof(sig) * 2); } return -1; } dkim->dkim_siglist[1] = NULL; dkim->dkim_siglist[0] = DKIM_MALLOC(dkim, sizeof *sig); if (dkim->dkim_siglist[0] == NULL) { (void) dkim_free(dkim); if (err != NULL) { snprintf(err, errlen, "unable to allocate %d byte(s)", sizeof *sig); } return -1; } sig = dkim->dkim_siglist[0]; memset(sig, '\0', sizeof *sig); sig->sig_domain = domain; sig->sig_selector = selector; dkim->dkim_user = dkim_strdup(dkim, "nobody", 0); if (dkim->dkim_user == NULL) { (void) dkim_free(dkim); return -1; } stat = dkim_get_key(dkim, sig); if (stat != DKIM_STAT_OK) { if (err != NULL) { const char *errstr; errstr = dkim_geterror(dkim); if (errstr != NULL) { sm_strlcpy(err, errstr, errlen); } else { sm_strlcpy(err, dkim_getresultstr(stat), errlen); } } (void) dkim_free(dkim); return -1; } if (key != NULL) { keybuf = BIO_new_mem_buf(key, keylen); if (keybuf == NULL) { if (err != NULL) { sm_strlcpy(err, "BIO_new_mem_buf() failed", errlen); } (void) dkim_free(dkim); return -1; } rsa = DKIM_MALLOC(dkim, sizeof(struct dkim_rsa)); if (rsa == NULL) { BIO_free(keybuf); (void) dkim_free(dkim); if (err != NULL) { snprintf(err, errlen, "unable to allocate %d byte(s)", sizeof(struct dkim_rsa)); } return -1; } memset(rsa, '\0', sizeof(struct dkim_rsa)); sig->sig_signature = (void *) rsa; sig->sig_keytype = DKIM_KEYTYPE_RSA; rsa->rsa_pkey = PEM_read_bio_PrivateKey(keybuf, NULL, NULL, NULL); if (rsa->rsa_pkey == NULL) { BIO_free(keybuf); (void) dkim_free(dkim); if (err != NULL) { sm_strlcpy(err, "PEM_read_bio_PrivateKey() failed", errlen); } return -1; } rsa->rsa_rsa = EVP_PKEY_get1_RSA(rsa->rsa_pkey); if (rsa->rsa_rsa == NULL) { BIO_free(keybuf); (void) dkim_free(dkim); if (err != NULL) { sm_strlcpy(err, "EVP_PKEY_get1_RSA() failed", errlen); } return -1; } rsa->rsa_keysize = RSA_size(rsa->rsa_rsa); rsa->rsa_pad = RSA_PKCS1_PADDING; outkey = BIO_new(BIO_s_mem()); if (outkey == NULL) { BIO_free(keybuf); (void) dkim_free(dkim); if (err != NULL) sm_strlcpy(err, "BIO_new() failed", errlen); return -1; } status = i2d_RSA_PUBKEY_bio(outkey, rsa->rsa_rsa); if (status == 0) { BIO_free(keybuf); BIO_free(outkey); (void) dkim_free(dkim); if (err != NULL) { sm_strlcpy(err, "i2d_RSA_PUBKEY_bio() failed", errlen); } return -1; } (void) BIO_get_mem_data(outkey, &ptr); if (BIO_number_written(outkey) == sig->sig_keylen) status = memcmp(ptr, sig->sig_key, sig->sig_keylen); else status = 1; if (status != 0) sm_strlcpy(err, "keys do not match", errlen); BIO_free(keybuf); BIO_free(outkey); } (void) dkim_free(dkim); return (status == 0 ? 0 : 1); } /* ** DKIM_TEST_SSP -- verify that a valid sender signing policy exists in dns ** ** Parameters: ** lib -- DKIM library handle ** domain -- domain name ** ** Return value: ** 0 -- some kind of result was made available ** -1 -- error */ int dkim_test_ssp(DKIM_LIB *lib, char *domain, dkim_policy_t *presult, dkim_handling_t *hresult, int *presult2, char *err, size_t errlen) { DKIM_STAT stat; bool test = FALSE; bool susp = FALSE; dkim_policy_t pcode = DKIM_POLICY_DEFAULT; dkim_handling_t hcode = DKIM_HANDLING_DEFAULT; DKIM *dkim; assert(lib != NULL); assert(presult != NULL); assert(hresult != NULL); assert(presult2 != NULL); dkim = dkim_verify(lib, "test", NULL, &stat); if (dkim == NULL) { if (err != NULL) sm_strlcpy(err, dkim_getresultstr(stat), errlen); return -1; } dkim->dkim_mode = DKIM_MODE_VERIFY; dkim->dkim_domain = domain; dkim->dkim_sigcount = 0; stat = dkim_policy(dkim, &test, &susp, &pcode, &hcode, NULL); if (stat != DKIM_STAT_OK) { if (err != NULL) { const char *errstr; errstr = dkim_geterror(dkim); if (errstr != NULL) { sm_strlcpy(err, errstr, errlen); } else { sm_strlcpy(err, dkim_getresultstr(stat), errlen); } } dkim->dkim_domain = NULL; (void) dkim_free(dkim); return -1; } *presult = pcode; *hresult = hcode; *presult2 = dkim_getpresult(dkim); dkim->dkim_domain = NULL; (void) dkim_free(dkim); return (stat == DKIM_STAT_OK ? 0 : -1); }