Exemple #1
0
void
SSL_SESSION_free(SSL_SESSION *ss)
{
	int i;

	if (ss == NULL)
		return;

	i = CRYPTO_add(&ss->references, -1, CRYPTO_LOCK_SSL_SESSION);
	if (i > 0)
		return;

	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->internal->ex_data);

	explicit_bzero(ss->master_key, sizeof ss->master_key);
	explicit_bzero(ss->session_id, sizeof ss->session_id);

	ssl_sess_cert_free(ss->internal->sess_cert);

	X509_free(ss->peer);

	sk_SSL_CIPHER_free(ss->ciphers);

	free(ss->tlsext_hostname);
	free(ss->tlsext_tick);
	free(ss->internal->tlsext_ecpointformatlist);
	free(ss->internal->tlsext_supportedgroups);

	freezero(ss->internal, sizeof(*ss->internal));
	freezero(ss, sizeof(*ss));
}
void
tls_keypair_clear_key(struct tls_keypair *keypair)
{
	freezero(keypair->key_mem, keypair->key_len);
	keypair->key_mem = NULL;
	keypair->key_len = 0;
}
Exemple #3
0
/* returns
 *      1: correct signature
 *      0: incorrect signature
 *     -1: error
 */
int
ECDSA_verify(int type, const unsigned char *dgst, int dgst_len,
    const unsigned char *sigbuf, int sig_len, EC_KEY *eckey)
{
	ECDSA_SIG *s;
	unsigned char *der = NULL;
	const unsigned char *p = sigbuf;
	int derlen = -1;
	int ret = -1;

	s = ECDSA_SIG_new();
	if (s == NULL)
		return (ret);
	if (d2i_ECDSA_SIG(&s, &p, sig_len) == NULL)
		goto err;
	/* Ensure signature uses DER and doesn't have trailing garbage */
	derlen = i2d_ECDSA_SIG(s, &der);
	if (derlen != sig_len || memcmp(sigbuf, der, derlen))
		goto err;
	ret = ECDSA_do_verify(dgst, dgst_len, s, eckey);

err:
	freezero(der, derlen);
	ECDSA_SIG_free(s);
	return (ret);
}
Exemple #4
0
EVP_PKEY *
b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u)
{
	unsigned char pvk_hdr[24], *buf = NULL;
	const unsigned char *p;
	size_t buflen;
	EVP_PKEY *ret = NULL;
	unsigned int saltlen, keylen;

	if (BIO_read(in, pvk_hdr, 24) != 24) {
		PEMerror(PEM_R_PVK_DATA_TOO_SHORT);
		return NULL;
	}
	p = pvk_hdr;

	if (!do_PVK_header(&p, 24, 0, &saltlen, &keylen))
		return 0;
	buflen = keylen + saltlen;
	buf = malloc(buflen);
	if (!buf) {
		PEMerror(ERR_R_MALLOC_FAILURE);
		return 0;
	}
	p = buf;
	if (BIO_read(in, buf, buflen) != buflen) {
		PEMerror(PEM_R_PVK_DATA_TOO_SHORT);
		goto err;
	}
	ret = do_PVK_body(&p, saltlen, keylen, cb, u);

err:
	freezero(buf, buflen);
	return ret;
}
Exemple #5
0
/*
 * data has already been hashed (probably with SHA or SHA-1).
 * returns
 *      1: correct signature
 *      0: incorrect signature
 *     -1: error
 */
int
DSA_verify(int type, const unsigned char *dgst, int dgst_len,
    const unsigned char *sigbuf, int siglen, DSA *dsa)
{
	DSA_SIG *s;
	unsigned char *der = NULL;
	const unsigned char *p = sigbuf;
	int derlen = -1;
	int ret = -1;

	s = DSA_SIG_new();
	if (s == NULL)
		return ret;
	if (d2i_DSA_SIG(&s, &p, siglen) == NULL)
		goto err;
	/* Ensure signature uses DER and doesn't have trailing garbage */
	derlen = i2d_DSA_SIG(s, &der);
	if (derlen != siglen || memcmp(sigbuf, der, derlen))
		goto err;
	ret = DSA_do_verify(dgst, dgst_len, s, dsa);
err:
	freezero(der, derlen);
	DSA_SIG_free(s);
	return ret;
}
void
ssh_digest_free(struct ssh_digest_ctx *ctx)
{
	if (ctx == NULL)
		return;
	EVP_MD_CTX_free(ctx->mdctx);
	freezero(ctx, sizeof(*ctx));
}
Exemple #7
0
int
tls_config_load_file(struct tls_error *error, const char *filetype,
    const char *filename, char **buf, size_t *len)
{
	struct stat st;
	int fd = -1;
	ssize_t n;

	free(*buf);
	*buf = NULL;
	*len = 0;

	if ((fd = open(filename, O_RDONLY)) == -1) {
		tls_error_set(error, "failed to open %s file '%s'",
		    filetype, filename);
		goto err;
	}
	if (fstat(fd, &st) != 0) {
		tls_error_set(error, "failed to stat %s file '%s'",
		    filetype, filename);
		goto err;
	}
	if (st.st_size < 0)
		goto err;
	*len = (size_t)st.st_size;
	if ((*buf = malloc(*len)) == NULL) {
		tls_error_set(error, "failed to allocate buffer for "
		    "%s file", filetype);
		goto err;
	}
	n = read(fd, *buf, *len);
	if (n < 0 || (size_t)n != *len) {
		tls_error_set(error, "failed to read %s file '%s'",
		    filetype, filename);
		goto err;
	}
	close(fd);
	return 0;

 err:
	if (fd != -1)
		close(fd);
	freezero(*buf, *len);
	*buf = NULL;
	*len = 0;

	return -1;
}
Exemple #8
0
static int
openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen,
    u_char *sigbuf, size_t siglen, RSA *rsa)
{
	size_t rsasize = 0, oidlen = 0, hlen = 0;
	int ret, len, oidmatch, hashmatch;
	const u_char *oid = NULL;
	u_char *decrypted = NULL;

	if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0)
		return ret;
	ret = SSH_ERR_INTERNAL_ERROR;
	hlen = ssh_digest_bytes(hash_alg);
	if (hashlen != hlen) {
		ret = SSH_ERR_INVALID_ARGUMENT;
		goto done;
	}
	rsasize = RSA_size(rsa);
	if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM ||
	    siglen == 0 || siglen > rsasize) {
		ret = SSH_ERR_INVALID_ARGUMENT;
		goto done;
	}
	if ((decrypted = malloc(rsasize)) == NULL) {
		ret = SSH_ERR_ALLOC_FAIL;
		goto done;
	}
	if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,
	    RSA_PKCS1_PADDING)) < 0) {
		ret = SSH_ERR_LIBCRYPTO_ERROR;
		goto done;
	}
	if (len < 0 || (size_t)len != hlen + oidlen) {
		ret = SSH_ERR_INVALID_FORMAT;
		goto done;
	}
	oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0;
	hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0;
	if (!oidmatch || !hashmatch) {
		ret = SSH_ERR_SIGNATURE_INVALID;
		goto done;
	}
	ret = 0;
done:
	freezero(decrypted, rsasize);
	return ret;
}
Exemple #9
0
static double
user_specific_delay(const char *user)
{
	char b[512];
	size_t len = ssh_digest_bytes(SSH_DIGEST_SHA512);
	u_char *hash = xmalloc(len);
	double delay;

	(void)snprintf(b, sizeof b, "%llu%s",
	     (unsigned long long)options.timing_secret, user);
	if (ssh_digest_memory(SSH_DIGEST_SHA512, b, strlen(b), hash, len) != 0)
		fatal("%s: ssh_digest_memory", __func__);
	/* 0-4.2 ms of delay */
	delay = (double)PEEK_U32(hash) / 1000 / 1000 / 1000 / 1000;
	freezero(hash, len);
	debug3("%s: user specific delay %0.3lfms", __func__, delay/1000);
	return MIN_FAIL_DELAY_SECONDS + delay;
}
Exemple #10
0
static void 
ec_pre_comp_clear_free(void *pre_)
{
	int i;
	EC_PRE_COMP *pre = pre_;

	if (!pre)
		return;

	i = CRYPTO_add(&pre->references, -1, CRYPTO_LOCK_EC_PRE_COMP);
	if (i > 0)
		return;

	if (pre->points) {
		EC_POINT **p;

		for (p = pre->points; *p != NULL; p++) {
			EC_POINT_clear_free(*p);
			explicit_bzero(p, sizeof *p);
		}
		free(pre->points);
	}
	freezero(pre, sizeof *pre);
}
Exemple #11
0
void
imsg_free(struct imsg *imsg)
{
	freezero(imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE);
}
Exemple #12
0
int
i2d_SSL_SESSION(SSL_SESSION *s, unsigned char **pp)
{
	CBB cbb, session, cipher_suite, session_id, master_key, time, timeout;
	CBB peer_cert, sidctx, verify_result, hostname, lifetime, ticket;
	CBB value;
	unsigned char *data = NULL, *peer_cert_bytes = NULL;
	size_t data_len = 0;
	int len, rv = -1;
	uint16_t cid;

	if (s == NULL)
		return (0);

	if (s->cipher == NULL && s->cipher_id == 0)
		return (0);

	if (!CBB_init(&cbb, 0))
		goto err;

	if (!CBB_add_asn1(&cbb, &session, CBS_ASN1_SEQUENCE))
		goto err;

	/* Session ASN1 version. */
	if (!CBB_add_asn1_uint64(&session, SSL_SESSION_ASN1_VERSION))
		goto err;

	/* TLS/SSL protocol version. */
	if (s->ssl_version < 0)
		goto err;
	if (!CBB_add_asn1_uint64(&session, s->ssl_version))
		goto err;

	/* Cipher suite ID. */
	/* XXX - require cipher to be non-NULL or always/only use cipher_id. */
	cid = (uint16_t)(s->cipher_id & 0xffff);
	if (s->cipher != NULL)
		cid = ssl3_cipher_get_value(s->cipher);
	if (!CBB_add_asn1(&session, &cipher_suite, CBS_ASN1_OCTETSTRING))
		goto err;
	if (!CBB_add_u16(&cipher_suite, cid))
		goto err;

	/* Session ID. */
	if (!CBB_add_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING))
		goto err;
	if (!CBB_add_bytes(&session_id, s->session_id, s->session_id_length))
		goto err;

	/* Master key. */
	if (!CBB_add_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING))
		goto err;
	if (!CBB_add_bytes(&master_key, s->master_key, s->master_key_length))
		goto err;

	/* Time [1]. */
	if (s->time != 0) {
		if (s->time < 0)
			goto err;
		if (!CBB_add_asn1(&session, &time, SSLASN1_TIME_TAG))
			goto err;
		if (!CBB_add_asn1_uint64(&time, s->time))
			goto err;
	}

	/* Timeout [2]. */
	if (s->timeout != 0) {
		if (s->timeout < 0)
			goto err;
		if (!CBB_add_asn1(&session, &timeout, SSLASN1_TIMEOUT_TAG))
			goto err;
		if (!CBB_add_asn1_uint64(&timeout, s->timeout))
			goto err;
	}

	/* Peer certificate [3]. */
	if (s->peer != NULL) {
		if ((len = i2d_X509(s->peer, &peer_cert_bytes)) <= 0)
			goto err;
		if (!CBB_add_asn1(&session, &peer_cert, SSLASN1_PEER_CERT_TAG))
			goto err;
		if (!CBB_add_bytes(&peer_cert, peer_cert_bytes, len))
			goto err;
	}

	/* Session ID context [4]. */
	/* XXX - Actually handle this as optional? */
	if (!CBB_add_asn1(&session, &sidctx, SSLASN1_SESSION_ID_CTX_TAG))
		goto err;
	if (!CBB_add_asn1(&sidctx, &value, CBS_ASN1_OCTETSTRING))
		goto err;
	if (!CBB_add_bytes(&value, s->sid_ctx, s->sid_ctx_length))
		goto err;

	/* Verify result [5]. */
	if (s->verify_result != X509_V_OK) {
		if (s->verify_result < 0)
			goto err;
		if (!CBB_add_asn1(&session, &verify_result,
		    SSLASN1_VERIFY_RESULT_TAG))
			goto err;
		if (!CBB_add_asn1_uint64(&verify_result, s->verify_result))
			goto err;
	}

	/* Hostname [6]. */
	if (s->tlsext_hostname != NULL) {
		if (!CBB_add_asn1(&session, &hostname, SSLASN1_HOSTNAME_TAG))
			goto err;
		if (!CBB_add_asn1(&hostname, &value, CBS_ASN1_OCTETSTRING))
			goto err;
		if (!CBB_add_bytes(&value, (const uint8_t *)s->tlsext_hostname,
		    strlen(s->tlsext_hostname)))
			goto err;
	}

	/* PSK identity hint [7]. */
	/* PSK identity [8]. */

	/* Ticket lifetime hint [9]. */
	if (s->tlsext_tick_lifetime_hint > 0) {
		if (!CBB_add_asn1(&session, &lifetime, SSLASN1_LIFETIME_TAG))
			goto err;
		if (!CBB_add_asn1_uint64(&lifetime,
		    s->tlsext_tick_lifetime_hint))
			goto err;
	}

	/* Ticket [10]. */
	if (s->tlsext_tick) {
		if (!CBB_add_asn1(&session, &ticket, SSLASN1_TICKET_TAG))
			goto err;
		if (!CBB_add_asn1(&ticket, &value, CBS_ASN1_OCTETSTRING))
			goto err;
		if (!CBB_add_bytes(&value, s->tlsext_tick, s->tlsext_ticklen))
			goto err;
	}

	/* Compression method [11]. */
	/* SRP username [12]. */

	if (!CBB_finish(&cbb, &data, &data_len))
		goto err;

	if (data_len > INT_MAX)
		goto err;

	if (pp != NULL) {
		if (*pp == NULL) {
			*pp = data;
			data = NULL;
		} else {
			memcpy(*pp, data, data_len);
			*pp += data_len;
		}
	}

	rv = (int)data_len;

 err:
	CBB_cleanup(&cbb);
	freezero(data, data_len);
	free(peer_cert_bytes);

	return rv;
}
Exemple #13
0
int
ASN1_item_sign_ctx(const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2,
    ASN1_BIT_STRING *signature, void *asn, EVP_MD_CTX *ctx)
{
	const EVP_MD *type;
	EVP_PKEY *pkey;
	unsigned char *buf_in = NULL, *buf_out = NULL;
	size_t inl = 0, outl = 0, outll = 0;
	int signid, paramtype;
	int rv;

	type = EVP_MD_CTX_md(ctx);
	pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx);

	if (!type || !pkey) {
		ASN1error(ASN1_R_CONTEXT_NOT_INITIALISED);
		return 0;
	}

	if (pkey->ameth->item_sign) {
		rv = pkey->ameth->item_sign(ctx, it, asn, algor1, algor2,
		    signature);
		if (rv == 1)
			outl = signature->length;
		/* Return value meanings:
		 * <=0: error.
		 *   1: method does everything.
		 *   2: carry on as normal.
		 *   3: ASN1 method sets algorithm identifiers: just sign.
		 */
		if (rv <= 0)
			ASN1error(ERR_R_EVP_LIB);
		if (rv <= 1)
			goto err;
	} else
		rv = 2;

	if (rv == 2) {
		if (type->flags & EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) {
			if (!pkey->ameth ||
			    !OBJ_find_sigid_by_algs(&signid,
				EVP_MD_nid(type), pkey->ameth->pkey_id)) {
				ASN1error(ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
				return 0;
			}
		} else
			signid = type->pkey_type;

		if (pkey->ameth->pkey_flags & ASN1_PKEY_SIGPARAM_NULL)
			paramtype = V_ASN1_NULL;
		else
			paramtype = V_ASN1_UNDEF;

		if (algor1)
			X509_ALGOR_set0(algor1,
			    OBJ_nid2obj(signid), paramtype, NULL);
		if (algor2)
			X509_ALGOR_set0(algor2,
			    OBJ_nid2obj(signid), paramtype, NULL);

	}

	inl = ASN1_item_i2d(asn, &buf_in, it);
	outll = outl = EVP_PKEY_size(pkey);
	buf_out = malloc(outl);
	if ((buf_in == NULL) || (buf_out == NULL)) {
		outl = 0;
		ASN1error(ERR_R_MALLOC_FAILURE);
		goto err;
	}

	if (!EVP_DigestSignUpdate(ctx, buf_in, inl) ||
	    !EVP_DigestSignFinal(ctx, buf_out, &outl)) {
		outl = 0;
		ASN1error(ERR_R_EVP_LIB);
		goto err;
	}
	free(signature->data);
	signature->data = buf_out;
	buf_out = NULL;
	signature->length = outl;
	/* In the interests of compatibility, I'll make sure that
	 * the bit string has a 'not-used bits' value of 0
	 */
	signature->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
	signature->flags |= ASN1_STRING_FLAG_BITS_LEFT;

err:
	EVP_MD_CTX_cleanup(ctx);
	freezero((char *)buf_in, inl);
	freezero((char *)buf_out, outll);
	return (outl);
}
Exemple #14
0
void
tls_unload_file(uint8_t *buf, size_t len)
{
	freezero(buf, len);
}
Exemple #15
0
uint8_t *
tls_load_file(const char *name, size_t *len, char *password)
{
	FILE *fp;
	EVP_PKEY *key = NULL;
	BIO *bio = NULL;
	char *data;
	uint8_t *buf = NULL;
	struct stat st;
	size_t size = 0;
	int fd = -1;
	ssize_t n;

	*len = 0;

	if ((fd = open(name, O_RDONLY)) == -1)
		return (NULL);

	/* Just load the file into memory without decryption */
	if (password == NULL) {
		if (fstat(fd, &st) != 0)
			goto fail;
		if (st.st_size < 0)
			goto fail;
		size = (size_t)st.st_size;
		if ((buf = malloc(size)) == NULL)
			goto fail;
		n = read(fd, buf, size);
		if (n < 0 || (size_t)n != size)
			goto fail;
		close(fd);
		goto done;
	}

	/* Or read the (possibly) encrypted key from file */
	if ((fp = fdopen(fd, "r")) == NULL)
		goto fail;
	fd = -1;

	key = PEM_read_PrivateKey(fp, NULL, tls_password_cb, password);
	fclose(fp);
	if (key == NULL)
		goto fail;

	/* Write unencrypted key to memory buffer */
	if ((bio = BIO_new(BIO_s_mem())) == NULL)
		goto fail;
	if (!PEM_write_bio_PrivateKey(bio, key, NULL, NULL, 0, NULL, NULL))
		goto fail;
	if ((size = BIO_get_mem_data(bio, &data)) <= 0)
		goto fail;
	if ((buf = malloc(size)) == NULL)
		goto fail;
	memcpy(buf, data, size);

	BIO_free_all(bio);
	EVP_PKEY_free(key);

 done:
	*len = size;
	return (buf);

 fail:
	if (fd != -1)
		close(fd);
	freezero(buf, size);
	BIO_free_all(bio);
	EVP_PKEY_free(key);

	return (NULL);
}
Exemple #16
0
/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
int
ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
    const u_char *data, size_t datalen, const char *alg_ident)
{
	const BIGNUM *rsa_n;
	u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL;
	size_t slen = 0;
	u_int dlen, len;
	int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
	struct sshbuf *b = NULL;

	if (lenp != NULL)
		*lenp = 0;
	if (sigp != NULL)
		*sigp = NULL;

	if (alg_ident == NULL || strlen(alg_ident) == 0)
		hash_alg = SSH_DIGEST_SHA1;
	else
		hash_alg = rsa_hash_id_from_keyname(alg_ident);
	if (key == NULL || key->rsa == NULL || hash_alg == -1 ||
	    sshkey_type_plain(key->type) != KEY_RSA)
		return SSH_ERR_INVALID_ARGUMENT;
	RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
	if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
		return SSH_ERR_KEY_LENGTH;
	slen = RSA_size(key->rsa);
	if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM)
		return SSH_ERR_INVALID_ARGUMENT;

	/* hash the data */
	nid = rsa_hash_alg_nid(hash_alg);
	if ((dlen = ssh_digest_bytes(hash_alg)) == 0)
		return SSH_ERR_INTERNAL_ERROR;
	if ((ret = ssh_digest_memory(hash_alg, data, datalen,
	    digest, sizeof(digest))) != 0)
		goto out;

	if ((sig = malloc(slen)) == NULL) {
		ret = SSH_ERR_ALLOC_FAIL;
		goto out;
	}

	if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) {
		ret = SSH_ERR_LIBCRYPTO_ERROR;
		goto out;
	}
	if (len < slen) {
		size_t diff = slen - len;
		memmove(sig + diff, sig, len);
		explicit_bzero(sig, diff);
	} else if (len > slen) {
		ret = SSH_ERR_INTERNAL_ERROR;
		goto out;
	}
	/* encode signature */
	if ((b = sshbuf_new()) == NULL) {
		ret = SSH_ERR_ALLOC_FAIL;
		goto out;
	}
	if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 ||
	    (ret = sshbuf_put_string(b, sig, slen)) != 0)
		goto out;
	len = sshbuf_len(b);
	if (sigp != NULL) {
		if ((*sigp = malloc(len)) == NULL) {
			ret = SSH_ERR_ALLOC_FAIL;
			goto out;
		}
		memcpy(*sigp, sshbuf_ptr(b), len);
	}
	if (lenp != NULL)
		*lenp = len;
	ret = 0;
 out:
	explicit_bzero(digest, sizeof(digest));
	freezero(sig, slen);
	sshbuf_free(b);
	return ret;
}
Exemple #17
0
int
dgst_main(int argc, char **argv)
{
	unsigned char *buf = NULL;
	int i, err = 1;
	const EVP_MD *md = NULL, *m;
	BIO *in = NULL, *inp;
	BIO *bmd = NULL;
	BIO *out = NULL;
#define PROG_NAME_SIZE  39
	char pname[PROG_NAME_SIZE + 1];
	int separator = 0;
	int debug = 0;
	int keyform = FORMAT_PEM;
	const char *outfile = NULL, *keyfile = NULL;
	const char *sigfile = NULL;
	int out_bin = -1, want_pub = 0, do_verify = 0;
	EVP_PKEY *sigkey = NULL;
	unsigned char *sigbuf = NULL;
	int siglen = 0;
	char *passargin = NULL, *passin = NULL;
	char *hmac_key = NULL;
	char *mac_name = NULL;
	STACK_OF(OPENSSL_STRING) * sigopts = NULL, *macopts = NULL;

	if (single_execution) {
		if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
			perror("pledge");
			exit(1);
		}
	}

	if ((buf = malloc(BUFSIZE)) == NULL) {
		BIO_printf(bio_err, "out of memory\n");
		goto end;
	}

	/* first check the program name */
	program_name(argv[0], pname, sizeof pname);

	md = EVP_get_digestbyname(pname);

	argc--;
	argv++;
	while (argc > 0) {
		if ((*argv)[0] != '-')
			break;
		if (strcmp(*argv, "-c") == 0)
			separator = 1;
		else if (strcmp(*argv, "-r") == 0)
			separator = 2;
		else if (strcmp(*argv, "-out") == 0) {
			if (--argc < 1)
				break;
			outfile = *(++argv);
		} else if (strcmp(*argv, "-sign") == 0) {
			if (--argc < 1)
				break;
			keyfile = *(++argv);
		} else if (!strcmp(*argv, "-passin")) {
			if (--argc < 1)
				break;
			passargin = *++argv;
		} else if (strcmp(*argv, "-verify") == 0) {
			if (--argc < 1)
				break;
			keyfile = *(++argv);
			want_pub = 1;
			do_verify = 1;
		} else if (strcmp(*argv, "-prverify") == 0) {
			if (--argc < 1)
				break;
			keyfile = *(++argv);
			do_verify = 1;
		} else if (strcmp(*argv, "-signature") == 0) {
			if (--argc < 1)
				break;
			sigfile = *(++argv);
		} else if (strcmp(*argv, "-keyform") == 0) {
			if (--argc < 1)
				break;
			keyform = str2fmt(*(++argv));
		}
		else if (strcmp(*argv, "-hex") == 0)
			out_bin = 0;
		else if (strcmp(*argv, "-binary") == 0)
			out_bin = 1;
		else if (strcmp(*argv, "-d") == 0)
			debug = 1;
		else if (!strcmp(*argv, "-hmac")) {
			if (--argc < 1)
				break;
			hmac_key = *++argv;
		} else if (!strcmp(*argv, "-mac")) {
			if (--argc < 1)
				break;
			mac_name = *++argv;
		} else if (strcmp(*argv, "-sigopt") == 0) {
			if (--argc < 1)
				break;
			if (!sigopts)
				sigopts = sk_OPENSSL_STRING_new_null();
			if (!sigopts || !sk_OPENSSL_STRING_push(sigopts, *(++argv)))
				break;
		} else if (strcmp(*argv, "-macopt") == 0) {
			if (--argc < 1)
				break;
			if (!macopts)
				macopts = sk_OPENSSL_STRING_new_null();
			if (!macopts || !sk_OPENSSL_STRING_push(macopts, *(++argv)))
				break;
		} else if ((m = EVP_get_digestbyname(&((*argv)[1]))) != NULL)
			md = m;
		else
			break;
		argc--;
		argv++;
	}


	if (do_verify && !sigfile) {
		BIO_printf(bio_err, "No signature to verify: use the -signature option\n");
		goto end;
	}
	if ((argc > 0) && (argv[0][0] == '-')) {	/* bad option */
		BIO_printf(bio_err, "unknown option '%s'\n", *argv);
		BIO_printf(bio_err, "options are\n");
		BIO_printf(bio_err, "-c              to output the digest with separating colons\n");
		BIO_printf(bio_err, "-r              to output the digest in coreutils format\n");
		BIO_printf(bio_err, "-d              to output debug info\n");
		BIO_printf(bio_err, "-hex            output as hex dump\n");
		BIO_printf(bio_err, "-binary         output in binary form\n");
		BIO_printf(bio_err, "-sign   file    sign digest using private key in file\n");
		BIO_printf(bio_err, "-verify file    verify a signature using public key in file\n");
		BIO_printf(bio_err, "-prverify file  verify a signature using private key in file\n");
		BIO_printf(bio_err, "-keyform arg    key file format (PEM)\n");
		BIO_printf(bio_err, "-out filename   output to filename rather than stdout\n");
		BIO_printf(bio_err, "-signature file signature to verify\n");
		BIO_printf(bio_err, "-sigopt nm:v    signature parameter\n");
		BIO_printf(bio_err, "-hmac key       create hashed MAC with key\n");
		BIO_printf(bio_err, "-mac algorithm  create MAC (not neccessarily HMAC)\n");
		BIO_printf(bio_err, "-macopt nm:v    MAC algorithm parameters or key\n");

		EVP_MD_do_all_sorted(list_md_fn, bio_err);
		goto end;
	}

	in = BIO_new(BIO_s_file());
	bmd = BIO_new(BIO_f_md());
	if (in == NULL || bmd == NULL) {
		ERR_print_errors(bio_err);
		goto end;
	}

	if (debug) {
		BIO_set_callback(in, BIO_debug_callback);
		/* needed for windows 3.1 */
		BIO_set_callback_arg(in, (char *) bio_err);
	}
	if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) {
		BIO_printf(bio_err, "Error getting password\n");
		goto end;
	}
	if (out_bin == -1) {
		if (keyfile)
			out_bin = 1;
		else
			out_bin = 0;
	}

	if (outfile) {
		if (out_bin)
			out = BIO_new_file(outfile, "wb");
		else
			out = BIO_new_file(outfile, "w");
	} else {
		out = BIO_new_fp(stdout, BIO_NOCLOSE);
	}

	if (!out) {
		BIO_printf(bio_err, "Error opening output file %s\n",
		    outfile ? outfile : "(stdout)");
		ERR_print_errors(bio_err);
		goto end;
	}
	if ((!!mac_name + !!keyfile + !!hmac_key) > 1) {
		BIO_printf(bio_err, "MAC and Signing key cannot both be specified\n");
		goto end;
	}
	if (keyfile) {
		if (want_pub)
			sigkey = load_pubkey(bio_err, keyfile, keyform, 0, NULL,
			    "key file");
		else
			sigkey = load_key(bio_err, keyfile, keyform, 0, passin,
			    "key file");
		if (!sigkey) {
			/*
			 * load_[pub]key() has already printed an appropriate
			 * message
			 */
			goto end;
		}
	}
	if (mac_name) {
		EVP_PKEY_CTX *mac_ctx = NULL;
		int r = 0;
		if (!init_gen_str(bio_err, &mac_ctx, mac_name, 0))
			goto mac_end;
		if (macopts) {
			char *macopt;
			for (i = 0; i < sk_OPENSSL_STRING_num(macopts); i++) {
				macopt = sk_OPENSSL_STRING_value(macopts, i);
				if (pkey_ctrl_string(mac_ctx, macopt) <= 0) {
					BIO_printf(bio_err,
					    "MAC parameter error \"%s\"\n",
					    macopt);
					ERR_print_errors(bio_err);
					goto mac_end;
				}
			}
		}
		if (EVP_PKEY_keygen(mac_ctx, &sigkey) <= 0) {
			BIO_puts(bio_err, "Error generating key\n");
			ERR_print_errors(bio_err);
			goto mac_end;
		}
		r = 1;
mac_end:
		if (mac_ctx)
			EVP_PKEY_CTX_free(mac_ctx);
		if (r == 0)
			goto end;
	}
	if (hmac_key) {
		sigkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL,
		    (unsigned char *) hmac_key, -1);
		if (!sigkey)
			goto end;
	}
	if (sigkey) {
		EVP_MD_CTX *mctx = NULL;
		EVP_PKEY_CTX *pctx = NULL;
		int r;
		if (!BIO_get_md_ctx(bmd, &mctx)) {
			BIO_printf(bio_err, "Error getting context\n");
			ERR_print_errors(bio_err);
			goto end;
		}
		if (do_verify)
			r = EVP_DigestVerifyInit(mctx, &pctx, md, NULL, sigkey);
		else
			r = EVP_DigestSignInit(mctx, &pctx, md, NULL, sigkey);
		if (!r) {
			BIO_printf(bio_err, "Error setting context\n");
			ERR_print_errors(bio_err);
			goto end;
		}
		if (sigopts) {
			char *sigopt;
			for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) {
				sigopt = sk_OPENSSL_STRING_value(sigopts, i);
				if (pkey_ctrl_string(pctx, sigopt) <= 0) {
					BIO_printf(bio_err,
					    "parameter error \"%s\"\n",
					    sigopt);
					ERR_print_errors(bio_err);
					goto end;
				}
			}
		}
	}
	/* we use md as a filter, reading from 'in' */
	else {
		if (md == NULL)
			md = EVP_md5();
		if (!BIO_set_md(bmd, md)) {
			BIO_printf(bio_err, "Error setting digest %s\n", pname);
			ERR_print_errors(bio_err);
			goto end;
		}
	}

	if (sigfile && sigkey) {
		BIO *sigbio;
		siglen = EVP_PKEY_size(sigkey);
		sigbuf = malloc(siglen);
		if (sigbuf == NULL) {
			BIO_printf(bio_err, "out of memory\n");
			ERR_print_errors(bio_err);
			goto end;
		}
		sigbio = BIO_new_file(sigfile, "rb");
		if (!sigbio) {
			BIO_printf(bio_err, "Error opening signature file %s\n",
			    sigfile);
			ERR_print_errors(bio_err);
			goto end;
		}
		siglen = BIO_read(sigbio, sigbuf, siglen);
		BIO_free(sigbio);
		if (siglen <= 0) {
			BIO_printf(bio_err, "Error reading signature file %s\n",
			    sigfile);
			ERR_print_errors(bio_err);
			goto end;
		}
	}
	inp = BIO_push(bmd, in);

	if (md == NULL) {
		EVP_MD_CTX *tctx;
		BIO_get_md_ctx(bmd, &tctx);
		md = EVP_MD_CTX_md(tctx);
	}
	if (argc == 0) {
		BIO_set_fp(in, stdin, BIO_NOCLOSE);
		err = do_fp(out, buf, inp, separator, out_bin, sigkey, sigbuf,
		    siglen, NULL, NULL, "stdin", bmd);
	} else {
		const char *md_name = NULL, *sig_name = NULL;
		if (!out_bin) {
			if (sigkey) {
				const EVP_PKEY_ASN1_METHOD *ameth;
				ameth = EVP_PKEY_get0_asn1(sigkey);
				if (ameth)
					EVP_PKEY_asn1_get0_info(NULL, NULL,
					    NULL, NULL, &sig_name, ameth);
			}
			md_name = EVP_MD_name(md);
		}
		err = 0;
		for (i = 0; i < argc; i++) {
			int r;
			if (BIO_read_filename(in, argv[i]) <= 0) {
				perror(argv[i]);
				err++;
				continue;
			} else {
				r = do_fp(out, buf, inp, separator, out_bin,
				    sigkey, sigbuf, siglen, sig_name, md_name,
				    argv[i], bmd);
			}
			if (r)
				err = r;
			(void) BIO_reset(bmd);
		}
	}

end:
	freezero(buf, BUFSIZE);
	if (in != NULL)
		BIO_free(in);
	free(passin);
	BIO_free_all(out);
	EVP_PKEY_free(sigkey);
	if (sigopts)
		sk_OPENSSL_STRING_free(sigopts);
	if (macopts)
		sk_OPENSSL_STRING_free(macopts);
	free(sigbuf);
	if (bmd != NULL)
		BIO_free(bmd);

	return (err);
}
Exemple #18
0
int
ssh_rsa_verify(const struct sshkey *key,
    const u_char *sig, size_t siglen, const u_char *data, size_t datalen,
    const char *alg)
{
	const BIGNUM *rsa_n;
	char *sigtype = NULL;
	int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR;
	size_t len = 0, diff, modlen, dlen;
	struct sshbuf *b = NULL;
	u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL;

	if (key == NULL || key->rsa == NULL ||
	    sshkey_type_plain(key->type) != KEY_RSA ||
	    sig == NULL || siglen == 0)
		return SSH_ERR_INVALID_ARGUMENT;
	RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
	if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
		return SSH_ERR_KEY_LENGTH;

	if ((b = sshbuf_from(sig, siglen)) == NULL)
		return SSH_ERR_ALLOC_FAIL;
	if (sshbuf_get_cstring(b, &sigtype, NULL) != 0) {
		ret = SSH_ERR_INVALID_FORMAT;
		goto out;
	}
	if ((hash_alg = rsa_hash_id_from_ident(sigtype)) == -1) {
		ret = SSH_ERR_KEY_TYPE_MISMATCH;
		goto out;
	}
	/*
	 * Allow ssh-rsa-cert-v01 certs to generate SHA2 signatures for
	 * legacy reasons, but otherwise the signature type should match.
	 */
	if (alg != NULL && strcmp(alg, "*****@*****.**") != 0) {
		if ((want_alg = rsa_hash_id_from_keyname(alg)) == -1) {
			ret = SSH_ERR_INVALID_ARGUMENT;
			goto out;
		}
		if (hash_alg != want_alg) {
			ret = SSH_ERR_SIGNATURE_INVALID;
			goto out;
		}
	}
	if (sshbuf_get_string(b, &sigblob, &len) != 0) {
		ret = SSH_ERR_INVALID_FORMAT;
		goto out;
	}
	if (sshbuf_len(b) != 0) {
		ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
		goto out;
	}
	/* RSA_verify expects a signature of RSA_size */
	modlen = RSA_size(key->rsa);
	if (len > modlen) {
		ret = SSH_ERR_KEY_BITS_MISMATCH;
		goto out;
	} else if (len < modlen) {
		diff = modlen - len;
		osigblob = sigblob;
		if ((sigblob = realloc(sigblob, modlen)) == NULL) {
			sigblob = osigblob; /* put it back for clear/free */
			ret = SSH_ERR_ALLOC_FAIL;
			goto out;
		}
		memmove(sigblob + diff, sigblob, len);
		explicit_bzero(sigblob, diff);
		len = modlen;
	}
	if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {
		ret = SSH_ERR_INTERNAL_ERROR;
		goto out;
	}
	if ((ret = ssh_digest_memory(hash_alg, data, datalen,
	    digest, sizeof(digest))) != 0)
		goto out;

	ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len,
	    key->rsa);
 out:
	freezero(sigblob, len);
	free(sigtype);
	sshbuf_free(b);
	explicit_bzero(digest, sizeof(digest));
	return ret;
}