/* $OpenBSD: signature.c,v 1.6 1999/08/16 02:33:37 angelos Exp $ */ /* * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu) * * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA, * in April-May 1998 * * Copyright (C) 1998, 1999 by Angelos D. Keromytis. * * Permission to use, copy, and modify this software without fee * is hereby granted, provided that this entire notice is included in * all copies of any software which is or includes a copy or * modification of this software. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR * PURPOSE. */ /* * Support for X509 keys and signing added by Ben Laurie * 3 May 1999 */ #include #include #include #include #include "keynote.h" #include "assertion.h" #include "signature.h" static const char hextab[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; /* * Actual conversion to hex. */ static void bin2hex(unsigned char *data, unsigned char *buffer, int len) { int off = 0; while(len > 0) { buffer[off++] = hextab[*data >> 4]; buffer[off++] = hextab[*data & 0xF]; data++; len--; } } /* * Encode a binary string with hex encoding. Return 0 on success. */ int kn_encode_hex(unsigned char *buf, char **dest, int len) { keynote_errno = 0; if (dest == (char **) NULL) { keynote_errno = ERROR_SYNTAX; return -1; } *dest = (char *) calloc(2 * len + 1, sizeof(char)); if (*dest == (char *) NULL) { keynote_errno = ERROR_MEMORY; return -1; } bin2hex(buf, *dest, len); return 0; } /* * Decode a hex encoding. Return 0 on success. The second argument * will be half as large as the first. */ int kn_decode_hex(char *hex, char **dest) { int i, decodedlen; char ptr[3]; keynote_errno = 0; if (dest == (char **) NULL) { keynote_errno = ERROR_SYNTAX; return -1; } if (strlen(hex) % 2) /* Should be even */ { keynote_errno = ERROR_SYNTAX; return -1; } decodedlen = strlen(hex) / 2; *dest = (char *) calloc(decodedlen, sizeof(char)); if (*dest == (char *) NULL) { keynote_errno = ERROR_MEMORY; return -1; } ptr[2] = '\0'; for (i = 0; i < decodedlen; i++) { ptr[0] = hex[2 * i]; ptr[1] = hex[(2 * i) + 1]; (*dest)[i] = (unsigned char) strtoul(ptr, (char **) NULL, 16); } return 0; } void keynote_free_key(void *key, int type) { if (key == (void *) NULL) return; #ifdef CRYPTO /* DSA keys */ if (type == KEYNOTE_ALGORITHM_DSA) { DSA_free(key); return; } /* RSA keys */ if (type == KEYNOTE_ALGORITHM_RSA) { RSA_free(key); return; } /* X509 keys */ if (type == KEYNOTE_ALGORITHM_X509) { RSA_free(key); /* RSA-specific */ return; } #endif /* CRYPTO */ #ifdef PGPLIB /* PGP keys */ if (type == KEYNOTE_ALGORITHM_PGP) { /* Unsupported yet */ return; } #endif /* PGPLIB */ /* BINARY keys */ if (type == KEYNOTE_ALGORITHM_BINARY) { free(((struct keynote_binary *) key)->bn_key); free(key); return; } /* Catch-all case */ if (type == KEYNOTE_ALGORITHM_NONE) free(key); } #if defined(CRYPTO) || defined(PGPLIB) /* * Map a signature to an algorithm. Return algorithm number (defined in * keynote.h), or KEYNOTE_ALGORITHM_NONE if unknown. * Also return in the second, third and fourth arguments the digest * algorithm, ASCII and internal encodings respectively. */ static int keynote_get_sig_algorithm(char *sig, int *hash, int *enc, int *internal) { if (sig == (char *) NULL) return KEYNOTE_ALGORITHM_NONE; if (!strncasecmp(SIG_DSA_SHA1_HEX, sig, SIG_DSA_SHA1_HEX_LEN)) { *hash = KEYNOTE_HASH_SHA1; *enc = ENCODING_HEX; *internal = INTERNAL_ENC_ASN1; return KEYNOTE_ALGORITHM_DSA; } if (!strncasecmp(SIG_DSA_SHA1_BASE64, sig, SIG_DSA_SHA1_BASE64_LEN)) { *hash = KEYNOTE_HASH_SHA1; *enc = ENCODING_BASE64; *internal = INTERNAL_ENC_ASN1; return KEYNOTE_ALGORITHM_DSA; } if (!strncasecmp(SIG_RSA_MD5_PKCS1_HEX, sig, SIG_RSA_MD5_PKCS1_HEX_LEN)) { *hash = KEYNOTE_HASH_MD5; *enc = ENCODING_HEX; *internal = INTERNAL_ENC_PKCS1; return KEYNOTE_ALGORITHM_RSA; } if (!strncasecmp(SIG_RSA_SHA1_PKCS1_HEX, sig, SIG_RSA_SHA1_PKCS1_HEX_LEN)) { *hash = KEYNOTE_HASH_SHA1; *enc = ENCODING_HEX; *internal = INTERNAL_ENC_PKCS1; return KEYNOTE_ALGORITHM_RSA; } if (!strncasecmp(SIG_RSA_MD5_PKCS1_BASE64, sig, SIG_RSA_MD5_PKCS1_BASE64_LEN)) { *hash = KEYNOTE_HASH_MD5; *enc = ENCODING_BASE64; *internal = INTERNAL_ENC_PKCS1; return KEYNOTE_ALGORITHM_RSA; } if (!strncasecmp(SIG_RSA_SHA1_PKCS1_BASE64, sig, SIG_RSA_SHA1_PKCS1_BASE64_LEN)) { *hash = KEYNOTE_HASH_SHA1; *enc = ENCODING_BASE64; *internal = INTERNAL_ENC_PKCS1; return KEYNOTE_ALGORITHM_RSA; } if (!strncasecmp(SIG_X509_SHA1_BASE64, sig, SIG_X509_SHA1_BASE64_LEN)) { *hash = KEYNOTE_HASH_SHA1; *enc = ENCODING_BASE64; *internal = INTERNAL_ENC_ASN1; return KEYNOTE_ALGORITHM_X509; } if (!strncasecmp(SIG_X509_SHA1_HEX, sig, SIG_X509_SHA1_HEX_LEN)) { *hash = KEYNOTE_HASH_SHA1; *enc = ENCODING_HEX; *internal = INTERNAL_ENC_ASN1; return KEYNOTE_ALGORITHM_X509; } #if 0 /* Not supported yet */ if (!strncasecmp(SIG_ELGAMAL_SHA1_HEX, sig, SIG_ELGAMAL_SHA1_HEX_LEN)) { *hash = KEYNOTE_HASH_SHA1; *enc = ENCODING_HEX; *internal = INTERNAL_ENC_ASN1; return KEYNOTE_ALGORITHM_ELGAMAL; } if (!strncasecmp(SIG_ELGAMAL_SHA1_BASE64, sig, SIG_ELGAMAL_SHA1_BASE64_LEN)) { *hash = KEYNOTE_HASH_SHA1; *enc = ENCODING_BASE64; *internal = INTERNAL_ENC_ASN1; return KEYNOTE_ALGORITHM_ELGAMAL; } #endif /* 0 */ #ifdef PGPLIB if (!strncasecmp(SIG_PGP_NATIVE, sig, SIG_PGP_NATIVE_LEN)) { *hash = KEYNOTE_HASH_NONE; *enc = ENCODING_NATIVE; *internal = INTERNAL_ENC_NATIVE; return KEYNOTE_ALGORITHM_PGP; } #endif /* PGPLIB */ *hash = KEYNOTE_HASH_NONE; *enc = ENCODING_NONE; *internal = INTERNAL_ENC_NONE; return KEYNOTE_ALGORITHM_NONE; } #endif /* CRYPTO || PGPLIB */ /* * Map a key to an algorithm. Return algorithm number (defined in * keynote.h), or KEYNOTE_ALGORITHM_NONE if unknown. * This latter is also a valid algorithm (for logical tags). Also return * in the second and third arguments the ASCII and internal encodings. */ int keynote_get_key_algorithm(char *key, int *encoding, int *internalencoding) { #ifdef CRYPTO if (!strncasecmp(DSA_HEX, key, DSA_HEX_LEN)) { *internalencoding = INTERNAL_ENC_ASN1; *encoding = ENCODING_HEX; return KEYNOTE_ALGORITHM_DSA; } if (!strncasecmp(DSA_BASE64, key, DSA_BASE64_LEN)) { *internalencoding = INTERNAL_ENC_ASN1; *encoding = ENCODING_BASE64; return KEYNOTE_ALGORITHM_DSA; } if (!strncasecmp(RSA_PKCS1_HEX, key, RSA_PKCS1_HEX_LEN)) { *internalencoding = INTERNAL_ENC_PKCS1; *encoding = ENCODING_HEX; return KEYNOTE_ALGORITHM_RSA; } if (!strncasecmp(RSA_PKCS1_BASE64, key, RSA_PKCS1_BASE64_LEN)) { *internalencoding = INTERNAL_ENC_PKCS1; *encoding = ENCODING_BASE64; return KEYNOTE_ALGORITHM_RSA; } if (!strncasecmp(X509_BASE64, key, X509_BASE64_LEN)) { *internalencoding = INTERNAL_ENC_ASN1; *encoding = ENCODING_BASE64; return KEYNOTE_ALGORITHM_X509; } if (!strncasecmp(X509_HEX, key, X509_HEX_LEN)) { *internalencoding = INTERNAL_ENC_ASN1; *encoding = ENCODING_HEX; return KEYNOTE_ALGORITHM_X509; } #if 0 /* Not supported yet */ if (!strncasecmp(ELGAMAL_HEX, key, ELGAMAL_HEX_LEN)) { *internalencoding = INTERNAL_ENC_ASN1; *encoding = ENCODING_HEX; return KEYNOTE_ALGORITHM_ELGAMAL; } if (!strncasecmp(ELGAMAL_BASE64, key, ELGAMAL_BASE64_LEN)) { *internalencoding = INTERNAL_ENC_ASN1; *encoding = ENCODING_BASE64; return KEYNOTE_ALGORITHM_ELGAMAL; } #endif /* 0 */ #endif /* CRYPTO */ #ifdef PGPLIB if (!strncasecmp(PGP_NATIVE, key, PGP_NATIVE_LEN)) { *internalencoding = INTERNAL_ENC_NATIVE; *encoding = ENCODING_NATIVE; return KEYNOTE_ALGORITHM_PGP; } #endif /* PGPLIB */ if (!strncasecmp(BINARY_HEX, key, BINARY_HEX_LEN)) { *internalencoding = INTERNAL_ENC_NONE; *encoding = ENCODING_HEX; return KEYNOTE_ALGORITHM_BINARY; } if (!strncasecmp(BINARY_BASE64, key, BINARY_BASE64_LEN)) { *internalencoding = INTERNAL_ENC_NONE; *encoding = ENCODING_BASE64; return KEYNOTE_ALGORITHM_BINARY; } *internalencoding = INTERNAL_ENC_NONE; *encoding = ENCODING_NONE; return KEYNOTE_ALGORITHM_NONE; } /* * Same as keynote_get_key_algorithm(), only verify that this is * a private key (just look at the prefix). */ static int keynote_get_private_key_algorithm(char *key, int *encoding, int *internalencoding) { if (strncasecmp(KEYNOTE_PRIVATE_KEY_PREFIX, key, KEYNOTE_PRIVATE_KEY_PREFIX_LEN)) { *internalencoding = INTERNAL_ENC_NONE; *encoding = ENCODING_NONE; return KEYNOTE_ALGORITHM_NONE; } return keynote_get_key_algorithm(key + KEYNOTE_PRIVATE_KEY_PREFIX_LEN, encoding, internalencoding); } /* * Decode a string to a key. Return 0 on success. */ int kn_decode_key(struct keynote_deckey *dc, char *key, int keytype) { #ifdef CRYPTO void *kk = (void *) NULL; X509 *px509Cert; EVP_PKEY *pPublicKey; #endif /* CRYPTO */ unsigned char *ptr = (char *) NULL, *decoded = (char *) NULL; int encoding, internalencoding, len = 0; keynote_errno = 0; if (keytype == KEYNOTE_PRIVATE_KEY) dc->dec_algorithm = keynote_get_private_key_algorithm(key, &encoding, &internalencoding); else dc->dec_algorithm = keynote_get_key_algorithm(key, &encoding, &internalencoding); if (dc->dec_algorithm == KEYNOTE_ALGORITHM_NONE) { dc->dec_key = (void *) strdup(key); if (dc->dec_key == (void *) NULL) { keynote_errno = ERROR_MEMORY; return -1; } return 0; } key = index(key, ':'); /* Move forward, to the Encoding. We're guaranteed * to have a ':' character, since this is a key */ key++; /* Remove ASCII encoding */ switch (encoding) { case ENCODING_NONE: break; case ENCODING_HEX: len = strlen(key) / 2; if (kn_decode_hex(key, (char **) &decoded) != 0) return -1; ptr = decoded; break; case ENCODING_BASE64: len = strlen(key); if (len % 4) /* Base64 encoding must be a multiple of 4 */ { keynote_errno = ERROR_SYNTAX; return -1; } len = 3 * (len / 4); decoded = (unsigned char *) calloc(len, sizeof(unsigned char)); ptr = decoded; if (decoded == (unsigned char *) NULL) { keynote_errno = ERROR_MEMORY; return -1; } if ((len = kn_decode_base64(key, decoded, len)) == -1) return -1; break; case ENCODING_NATIVE: decoded = strdup(key); if (decoded == (unsigned char *) NULL) { keynote_errno = ERROR_MEMORY; return -1; } len = strlen(key); ptr = decoded; break; default: keynote_errno = ERROR_SYNTAX; return -1; } #ifdef CRYPTO /* DSA-HEX */ if ((dc->dec_algorithm == KEYNOTE_ALGORITHM_DSA) && (internalencoding == INTERNAL_ENC_ASN1)) { dc->dec_key = DSA_new(); if (dc->dec_key == (DSA *) NULL) { keynote_errno = ERROR_MEMORY; return -1; } kk = dc->dec_key; if (keytype == KEYNOTE_PRIVATE_KEY) { if (d2i_DSAPrivateKey((DSA **) &kk, &decoded, len) == (DSA *) NULL) { if (ptr != (unsigned char *) NULL) free(ptr); DSA_free(kk); keynote_errno = ERROR_SYNTAX; /* Could be a memory error */ return -1; } } else { if (d2i_DSAPublicKey((DSA **) &kk, &decoded, len) == (DSA *) NULL) { if (ptr != (unsigned char *) NULL) free(ptr); DSA_free(kk); keynote_errno = ERROR_SYNTAX; /* Could be a memory error */ return -1; } } if (ptr != (unsigned char *) NULL) free(ptr); return 0; } /* RSA-PKCS1-HEX */ if ((dc->dec_algorithm == KEYNOTE_ALGORITHM_RSA) && (internalencoding == INTERNAL_ENC_PKCS1)) { dc->dec_key = RSA_new(); if (dc->dec_key == (RSA *) NULL) { keynote_errno = ERROR_MEMORY; return -1; } kk = dc->dec_key; if (keytype == KEYNOTE_PRIVATE_KEY) { if (d2i_RSAPrivateKey((RSA **) &kk, &decoded, len) == (RSA *) NULL) { if (ptr != (unsigned char *) NULL) free(ptr); RSA_free(kk); keynote_errno = ERROR_SYNTAX; /* Could be a memory error */ return -1; } } else { if (d2i_RSAPublicKey((RSA **) &kk, &decoded, len) == (RSA *) NULL) { if (ptr != (unsigned char *) NULL) free(ptr); RSA_free(kk); keynote_errno = ERROR_SYNTAX; /* Could be a memory error */ return -1; } } if (ptr != (unsigned char *) NULL) free(ptr); return 0; } /* X509 Cert */ if ((dc->dec_algorithm == KEYNOTE_ALGORITHM_X509) && (internalencoding == INTERNAL_ENC_ASN1) && (keytype == KEYNOTE_PUBLIC_KEY)) { if ((px509Cert = X509_new()) == (X509 *) NULL) { if (ptr) free(ptr); keynote_errno = ERROR_MEMORY; return -1; } if(d2i_X509(&px509Cert, &decoded, len) == NULL) { if (ptr) free(ptr); X509_free(px509Cert); keynote_errno = ERROR_SYNTAX; return -1; } if ((pPublicKey = X509_get_pubkey(px509Cert)) == (EVP_PKEY *) NULL) { if (ptr) free(ptr); X509_free(px509Cert); keynote_errno = ERROR_SYNTAX; return -1; } /* RSA-specific */ dc->dec_key = pPublicKey->pkey.rsa; if(ptr) free(ptr); return 0; } #endif /* CRYPTO */ /* BINARY keys */ if ((dc->dec_algorithm == KEYNOTE_ALGORITHM_BINARY) && (internalencoding == INTERNAL_ENC_NONE)) { dc->dec_key = (void *) calloc(1, sizeof(struct keynote_binary)); if (dc->dec_key == (struct keynote_binary *) NULL) { keynote_errno = ERROR_MEMORY; return -1; } ((struct keynote_binary *) dc->dec_key)->bn_key = decoded; ((struct keynote_binary *) dc->dec_key)->bn_len = len; return RESULT_TRUE; } /* Add support for more algorithms here */ if (ptr != (unsigned char *) NULL) free(ptr); /* This shouldn't ever be reached really */ keynote_errno = ERROR_SYNTAX; return -1; } /* * Compare two keys for equality. Return RESULT_TRUE if equal, * RESULT_FALSE otherwise. */ int kn_keycompare(void *key1, void *key2, int algorithm) { #ifdef CRYPTO DSA *p1, *p2; RSA *p3, *p4; #endif /* CRYPTO */ struct keynote_binary *bn1, *bn2; if ((key1 == (void *) NULL) || (key2 == (void *) NULL)) return RESULT_FALSE; switch (algorithm) { case KEYNOTE_ALGORITHM_NONE: if (!strcmp((char *) key1, (char *) key2)) return RESULT_TRUE; else return RESULT_FALSE; case KEYNOTE_ALGORITHM_DSA: #ifdef CRYPTO p1 = (DSA *) key1; p2 = (DSA *) key2; if (!BN_cmp(p1->p, p2->p) && !BN_cmp(p1->q, p2->q) && !BN_cmp(p1->g, p2->g) && !BN_cmp(p1->pub_key, p2->pub_key)) return RESULT_TRUE; else return RESULT_FALSE; #else /* CRYPTO */ return RESULT_FALSE; #endif /* CRYPTO */ case KEYNOTE_ALGORITHM_RSA: #ifdef CRYPTO p3 = (RSA *) key1; p4 = (RSA *) key2; if (!BN_cmp(p3->n, p4->n) && !BN_cmp(p3->e, p4->e)) return RESULT_TRUE; else return RESULT_FALSE; #else /* CRYPTO */ return RETURN_FALSE; #endif /* CRYPTO */ case KEYNOTE_ALGORITHM_ELGAMAL: /* Not supported yet */ return RESULT_FALSE; case KEYNOTE_ALGORITHM_PGP: /* Not supported yet */ return RESULT_FALSE; case KEYNOTE_ALGORITHM_BINARY: bn1 = (struct keynote_binary *) key1; bn2 = (struct keynote_binary *) key2; if ((bn1->bn_len == bn2->bn_len) && !memcmp(bn1->bn_key, bn2->bn_key, bn1->bn_len)) return RESULT_TRUE; else return RESULT_FALSE; default: return RESULT_FALSE; } } /* * Verify the signature on an assertion; return SIGRESULT_TRUE is * success, SIGRESULT_FALSE otherwise. */ int keynote_sigverify_assertion(struct assertion *as) { #if defined(CRYPTO) || defined(PGPLIB) int hashtype, enc, intenc, alg = KEYNOTE_ALGORITHM_NONE, hashlen = 0; unsigned char *sig, *decoded = (char *) NULL, *ptr; #ifdef CRYPTO unsigned char res2[20]; SHA_CTX shscontext; MD5_CTX md5context; int len = 0; DSA *dsa; RSA *rsa; #endif /* CRYPTO */ if ((as->as_signature == (char *) NULL) || (as->as_startofsignature == (char *) NULL) || (as->as_allbutsignature == (char *) NULL) || (as->as_allbutsignature - as->as_startofsignature <= 0)) return SIGRESULT_FALSE; alg = keynote_get_sig_algorithm(as->as_signature, &hashtype, &enc, &intenc); if (alg == KEYNOTE_ALGORITHM_NONE) return SIGRESULT_FALSE; /* Check for matching algorithms */ if (alg != as->as_signeralgorithm) return SIGRESULT_FALSE; sig = index(as->as_signature, ':'); /* Move forward to the Encoding. We * are guaranteed to have a ':' * character, since this is a valid * signature */ sig++; switch (hashtype) { case KEYNOTE_HASH_SHA1: #ifdef CRYPTO hashlen = 20; memset(res2, 0, hashlen); SHA1_Init(&shscontext); SHA1_Update(&shscontext, as->as_startofsignature, as->as_allbutsignature - as->as_startofsignature); SHA1_Update(&shscontext, as->as_signature, (char *) sig - as->as_signature); SHA1_Final(res2, &shscontext); #endif /* CRYPTO */ break; case KEYNOTE_HASH_MD5: #ifdef CRYPTO hashlen = 16; memset(res2, 0, hashlen); MD5_Init(&md5context); MD5_Update(&md5context, as->as_startofsignature, as->as_allbutsignature - as->as_startofsignature); MD5_Update(&md5context, as->as_signature, (char *) sig - as->as_signature); MD5_Final(res2, &md5context); #endif /* CRYPTO */ break; case KEYNOTE_HASH_NONE: break; } /* Remove ASCII encoding */ switch (enc) { case ENCODING_NONE: ptr = (char *) NULL; break; case ENCODING_HEX: len = strlen(sig) / 2; if (kn_decode_hex(sig, (char **) &decoded) != 0) return -1; ptr = decoded; break; case ENCODING_BASE64: len = strlen(sig); if (len % 4) /* Base64 encoding must be a multiple of 4 */ { keynote_errno = ERROR_SYNTAX; return -1; } len = 3 * (len / 4); decoded = (unsigned char *) calloc(len, sizeof(unsigned char)); ptr = decoded; if (decoded == (unsigned char *) NULL) { keynote_errno = ERROR_MEMORY; return -1; } len = kn_decode_base64(sig, decoded, len); if ((len == -1) || (len == 0) || (len == 1)) return -1; break; case ENCODING_NATIVE: decoded = (unsigned char *) strdup(sig); if (decoded == (unsigned char *) NULL) { keynote_errno = ERROR_MEMORY; return -1; } len = strlen(sig); ptr = decoded; break; default: keynote_errno = ERROR_SYNTAX; return -1; } /* DSA */ if ((alg == KEYNOTE_ALGORITHM_DSA) && (intenc == INTERNAL_ENC_ASN1)) { dsa = (DSA *) as->as_authorizer; if (DSA_verify(0, res2, hashlen, decoded, len, dsa) == 1) { if (ptr != (unsigned char *) NULL) free(ptr); return SIGRESULT_TRUE; } } else /* RSA */ if ((alg == KEYNOTE_ALGORITHM_RSA) && (intenc == INTERNAL_ENC_PKCS1)) { rsa = (RSA *) as->as_authorizer; if (RSA_verify_ASN1_OCTET_STRING(RSA_PKCS1_PADDING, res2, hashlen, decoded, len, rsa) == 1) { if (ptr != (unsigned char *) NULL) free(ptr); return SIGRESULT_TRUE; } } else if ((alg == KEYNOTE_ALGORITHM_X509) && (intenc == INTERNAL_ENC_ASN1)) { /* RSA-specific */ rsa = (RSA *) as->as_authorizer; if (RSA_verify(NID_shaWithRSAEncryption, res2, hashlen, decoded, len, rsa) == 1) { if (ptr != (unsigned char *) NULL) free(ptr); return SIGRESULT_TRUE; } } /* Handle more algorithms here */ if (ptr != (unsigned char *) NULL) free(ptr); #endif /* CRYPTO || PGPLIB */ return SIGRESULT_FALSE; } /* * Sign an assertion. */ static char * keynote_sign_assertion(struct assertion *as, char *sigalg, void *key, int keyalg, int verifyflag) { #if defined(CRYPTO) || defined(PGPLIB) #ifdef CRYPTO int slen, i, hashlen = 0, hashtype, alg, encoding, internalenc; unsigned char *sig = (char *) NULL, *finalbuf = (char *) NULL; unsigned char res2[LARGEST_HASH_SIZE], *sbuf = (char *) NULL; BIO *biokey = (BIO *) NULL; DSA *dsa = (DSA *) NULL; RSA *rsa = (RSA *) NULL; SHA_CTX shscontext; MD5_CTX md5context; #endif /* CRYPTO */ if ((as->as_signature_string_s == (char *) NULL) || (as->as_startofsignature == (char *) NULL) || (as->as_allbutsignature == (char *) NULL) || (as->as_allbutsignature - as->as_startofsignature <= 0) || (as->as_authorizer == (void *) NULL) || (key == (void *) NULL) || (as->as_signeralgorithm == KEYNOTE_ALGORITHM_NONE)) { keynote_errno = ERROR_SYNTAX; return (char *) NULL; } alg = keynote_get_sig_algorithm(sigalg, &hashtype, &encoding, &internalenc); if ((alg != as->as_signeralgorithm) || (alg != keyalg)) { keynote_errno = ERROR_SYNTAX; return (char *) NULL; } sig = index(sigalg, ':'); if (sig == (unsigned char *) NULL) { keynote_errno = ERROR_SYNTAX; return (char *) NULL; } sig++; switch (hashtype) { case KEYNOTE_HASH_SHA1: #ifdef CRYPTO hashlen = 20; memset(res2, 0, hashlen); SHA1_Init(&shscontext); SHA1_Update(&shscontext, as->as_startofsignature, as->as_allbutsignature - as->as_startofsignature); SHA1_Update(&shscontext, sigalg, (char *) sig - sigalg); SHA1_Final(res2, &shscontext); #endif /* CRYPTO */ break; case KEYNOTE_HASH_MD5: #ifdef CRYPTO hashlen = 16; memset(res2, 0, hashlen); MD5_Init(&md5context); MD5_Update(&md5context, as->as_startofsignature, as->as_allbutsignature - as->as_startofsignature); MD5_Update(&md5context, sigalg, (char *) sig - sigalg); MD5_Final(res2, &md5context); #endif /* CRYPTO */ break; case KEYNOTE_HASH_NONE: break; } #ifdef CRYPTO if ((alg == KEYNOTE_ALGORITHM_DSA) && (hashtype == KEYNOTE_HASH_SHA1) && (internalenc == INTERNAL_ENC_ASN1) && ((encoding == ENCODING_HEX) || (encoding == ENCODING_BASE64))) { dsa = (DSA *) key; sbuf = (unsigned char *) calloc(DSA_size(dsa), sizeof(unsigned char)); if (sbuf == (unsigned char *) NULL) { keynote_errno = ERROR_MEMORY; return (char *) NULL; } if (DSA_sign(0, res2, hashlen, sbuf, &slen, dsa) <= 0) { free(sbuf); keynote_errno = ERROR_SYNTAX; return (char *) NULL; } } else if ((alg == KEYNOTE_ALGORITHM_RSA) && ((hashtype == KEYNOTE_HASH_SHA1) || (hashtype == KEYNOTE_HASH_MD5)) && (internalenc == INTERNAL_ENC_PKCS1) && ((encoding == ENCODING_HEX) || (encoding == ENCODING_BASE64))) { rsa = (RSA *) key; sbuf = (unsigned char *) calloc(RSA_size(rsa), sizeof(unsigned char)); if (sbuf == (unsigned char *) NULL) { keynote_errno = ERROR_MEMORY; return (char *) NULL; } if (RSA_sign_ASN1_OCTET_STRING(RSA_PKCS1_PADDING, res2, hashlen, sbuf, &slen, rsa) <= 0) { free(sbuf); keynote_errno = ERROR_SYNTAX; return (char *) NULL; } } else if ((alg == KEYNOTE_ALGORITHM_X509) && (hashtype == KEYNOTE_HASH_SHA1) && (internalenc == INTERNAL_ENC_ASN1)) { if ((biokey = BIO_new(BIO_s_mem())) == (BIO *) NULL) { keynote_errno = ERROR_SYNTAX; return (char *) NULL; } if (BIO_write(biokey, key, strlen(key) + 1) <= 0) { BIO_free(biokey); keynote_errno = ERROR_SYNTAX; return (char *) NULL; } /* RSA-specific */ #if SSLEAY_VERSION_NUMBER >= 0x00904 rsa = (RSA *) PEM_read_bio_RSAPrivateKey(biokey, NULL, NULL, NULL); #else /* SSLEAY_VERSION_NUMBER */ rsa = (RSA *) PEM_read_bio_RSAPrivateKey(biokey, NULL, NULL); #endif /* SSLEAY_VERSION_NUMBER */ if (rsa == (RSA *) NULL) { BIO_free(biokey); keynote_errno = ERROR_SYNTAX; return (char *) NULL; } sbuf = calloc(RSA_size(rsa), sizeof(char)); if (sbuf == (unsigned char *) NULL) { BIO_free(biokey); RSA_free(rsa); keynote_errno = ERROR_MEMORY; return (char *) NULL; } if (RSA_sign(NID_shaWithRSAEncryption, res2, hashlen, sbuf, &slen, rsa) <= 0) { BIO_free(biokey); RSA_free(rsa); free(sbuf); keynote_errno = ERROR_SIGN_FAILURE; return NULL; } BIO_free(biokey); RSA_free(rsa); } else /* Other algorithms here */ { keynote_errno = ERROR_SYNTAX; return (char *) NULL; } /* ASCII encoding */ switch (encoding) { case ENCODING_HEX: i = kn_encode_hex(sbuf, (char **) &finalbuf, slen); free(sbuf); if (i != 0) return (char *) NULL; break; case ENCODING_BASE64: finalbuf = (unsigned char *) calloc(2 * slen, sizeof(unsigned char)); if (finalbuf == (unsigned char *) NULL) { keynote_errno = ERROR_MEMORY; free(sbuf); return (char *) NULL; } if ((slen = kn_encode_base64(sbuf, slen, finalbuf, 2 * slen)) == -1) { free(sbuf); return (char *) NULL; } break; default: free(sbuf); keynote_errno = ERROR_SYNTAX; return (char *) NULL; } /* Replace as->as_signature */ as->as_signature = (char *) calloc(strlen(sigalg) + strlen(finalbuf) + 1, sizeof(char)); if (as->as_signature == (char *) NULL) { free(finalbuf); keynote_errno = ERROR_MEMORY; return (char *) NULL; } /* Concatenate algorithm name and signature value */ sprintf(as->as_signature, "%s%s", sigalg, finalbuf); free(finalbuf); finalbuf = as->as_signature; /* Verify the newly-created signature if requested */ if (verifyflag) { /* Do the signature verification */ if (keynote_sigverify_assertion(as) != SIGRESULT_TRUE) { as->as_signature = (char *) NULL; free(finalbuf); if (keynote_errno == 0) keynote_errno = ERROR_SYNTAX; return (char *) NULL; } as->as_signature = (char *) NULL; } else as->as_signature = (char *) NULL; /* Everything ok */ return (char *) finalbuf; #endif /* CRYPTO */ #else /* CRYPTO || PGPLIB */ keynote_errno = ERROR_SYNTAX; return (char *) NULL; #endif /* CRYPTO || PGPLIB */ } /* * Verify the signature on an assertion. */ int kn_verify_assertion(char *buf, int len) { struct assertion *as; int res; keynote_errno = 0; as = keynote_parse_assertion(buf, len, ASSERT_FLAG_SIGVER); if (as == (struct assertion *) NULL) return -1; res = keynote_sigverify_assertion(as); keynote_free_assertion(as); return res; } /* * Produce the signature for an assertion. */ char * kn_sign_assertion(char *buf, int buflen, char *key, char *sigalg, int vflag) { int i, alg, hashtype, encoding, internalenc; struct keynote_deckey dc; struct assertion *as; char *s, *sig; keynote_errno = 0; s = (char *) NULL; if ((sigalg == (char *) NULL) || (buf == (char *) NULL) || (key == (char *) NULL)) { keynote_errno = ERROR_NOTFOUND; return (char *) NULL; } if (sigalg[strlen(sigalg) - 1] != ':') { keynote_errno = ERROR_SYNTAX; return (char *) NULL; } /* We're using a different format for X509 private keys, so... */ alg = keynote_get_sig_algorithm(sigalg, &hashtype, &encoding, &internalenc); if (alg != KEYNOTE_ALGORITHM_X509) { /* Parse the private key */ s = keynote_get_private_key(key); if (s == (char *) NULL) return (char *) NULL; /* Decode private key */ i = kn_decode_key(&dc, s, KEYNOTE_PRIVATE_KEY); if (i == -1) { free(s); return (char *) NULL; } } else /* X509 private key */ { dc.dec_key = key; dc.dec_algorithm = alg; } as = keynote_parse_assertion(buf, buflen, ASSERT_FLAG_SIGGEN); if (as == (struct assertion *) NULL) { if (alg != KEYNOTE_ALGORITHM_X509) { keynote_free_key(dc.dec_key, dc.dec_algorithm); free(s); } return (char *) NULL; } sig = keynote_sign_assertion(as, sigalg, dc.dec_key, dc.dec_algorithm, vflag); if (alg != KEYNOTE_ALGORITHM_X509) keynote_free_key(dc.dec_key, dc.dec_algorithm); keynote_free_assertion(as); if (s != (char *) NULL) free(s); return sig; } /* * ASCII-encode a key. */ char * kn_encode_key(struct keynote_deckey *dc, int iencoding, int encoding, int keytype) { #ifdef CRYPTO char *foo, *ptr; DSA *dsa; RSA *rsa; int i; #endif /* CRYPTO */ struct keynote_binary *bn; char *s; keynote_errno = 0; if ((dc == (struct keynote_deckey *) NULL) || (dc->dec_key == (void *) NULL)) { keynote_errno = ERROR_NOTFOUND; return (char *) NULL; } #ifdef CRYPTO /* DSA keys */ if ((dc->dec_algorithm == KEYNOTE_ALGORITHM_DSA) && (iencoding == INTERNAL_ENC_ASN1) && ((encoding == ENCODING_HEX) || (encoding == ENCODING_BASE64))) { dsa = (DSA *) dc->dec_key; if (keytype == KEYNOTE_PUBLIC_KEY) i = i2d_DSAPublicKey(dsa, NULL); else i = i2d_DSAPrivateKey(dsa, NULL); if (i <= 0) { keynote_errno = ERROR_SYNTAX; return (char *) NULL; } ptr = foo = (char *) calloc(i, sizeof(char)); if (foo == (char *) NULL) { keynote_errno = ERROR_MEMORY; return (char *) NULL; } dsa->write_params = 1; if (keytype == KEYNOTE_PUBLIC_KEY) i2d_DSAPublicKey(dsa, (unsigned char **) &foo); else i2d_DSAPrivateKey(dsa, (unsigned char **) &foo); if (encoding == ENCODING_HEX) { if (kn_encode_hex(ptr, &s, i) != 0) { free(ptr); return (char *) NULL; } free(ptr); return s; } else if (encoding == ENCODING_BASE64) { s = (char *) calloc(2 * i, sizeof(char)); if (s == (char *) NULL) { free(ptr); keynote_errno = ERROR_MEMORY; return (char *) NULL; } if (kn_encode_base64(ptr, i, s, 2 * i) == -1) { free(s); free(ptr); return (char *) NULL; } free(ptr); return s; } } /* RSA keys */ if ((dc->dec_algorithm == KEYNOTE_ALGORITHM_RSA) && (iencoding == INTERNAL_ENC_PKCS1) && ((encoding == ENCODING_HEX) || (encoding == ENCODING_BASE64))) { rsa = (RSA *) dc->dec_key; if (keytype == KEYNOTE_PUBLIC_KEY) i = i2d_RSAPublicKey(rsa, NULL); else i = i2d_RSAPrivateKey(rsa, NULL); if (i <= 0) { keynote_errno = ERROR_SYNTAX; return (char *) NULL; } ptr = foo = (char *) calloc(i, sizeof(char)); if (foo == (char *) NULL) { keynote_errno = ERROR_MEMORY; return (char *) NULL; } if (keytype == KEYNOTE_PUBLIC_KEY) i2d_RSAPublicKey(rsa, (unsigned char **) &foo); else i2d_RSAPrivateKey(rsa, (unsigned char **) &foo); if (encoding == ENCODING_HEX) { if (kn_encode_hex(ptr, &s, i) != 0) { free(ptr); return (char *) NULL; } free(ptr); return s; } else if (encoding == ENCODING_BASE64) { s = (char *) calloc(2 * i, sizeof(char)); if (s == (char *) NULL) { free(ptr); keynote_errno = ERROR_MEMORY; return (char *) NULL; } if (kn_encode_base64(ptr, i, s, 2 * i) == -1) { free(s); free(ptr); return (char *) NULL; } free(ptr); return s; } } #endif /* CRYPTO */ /* BINARY keys */ if ((dc->dec_algorithm == KEYNOTE_ALGORITHM_BINARY) && (iencoding == INTERNAL_ENC_NONE) && ((encoding == ENCODING_HEX) || (encoding == ENCODING_BASE64))) { bn = (struct keynote_binary *) dc->dec_key; if (encoding == ENCODING_HEX) { if (kn_encode_hex(bn->bn_key, &s, bn->bn_len) != 0) return (char *) NULL; return s; } else if (encoding == ENCODING_BASE64) { s = (char *) calloc(2 * bn->bn_len, sizeof(char)); if (s == (char *) NULL) { keynote_errno = ERROR_MEMORY; return (char *) NULL; } if (kn_encode_base64(bn->bn_key, bn->bn_len, s, 2 * bn->bn_len) == -1) { free(s); return (char *) NULL; } return s; } } keynote_errno = ERROR_NOTFOUND; return (char *) NULL; }