Home | History | Annotate | Download | only in tls
      1 /*
      2  * PKCS #1 (RSA Encryption)
      3  * Copyright (c) 2006-2009, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License version 2 as
      7  * published by the Free Software Foundation.
      8  *
      9  * Alternatively, this software may be distributed under the terms of BSD
     10  * license.
     11  *
     12  * See README and COPYING for more details.
     13  */
     14 
     15 #include "includes.h"
     16 
     17 #include "common.h"
     18 #include "rsa.h"
     19 #include "pkcs1.h"
     20 
     21 
     22 static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
     23 					   const u8 *in, size_t inlen,
     24 					   u8 *out, size_t *outlen)
     25 {
     26 	size_t ps_len;
     27 	u8 *pos;
     28 
     29 	/*
     30 	 * PKCS #1 v1.5, 8.1:
     31 	 *
     32 	 * EB = 00 || BT || PS || 00 || D
     33 	 * BT = 00 or 01 for private-key operation; 02 for public-key operation
     34 	 * PS = k-3-||D||; at least eight octets
     35 	 * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero)
     36 	 * k = length of modulus in octets (modlen)
     37 	 */
     38 
     39 	if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) {
     40 		wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer "
     41 			   "lengths (modlen=%lu outlen=%lu inlen=%lu)",
     42 			   __func__, (unsigned long) modlen,
     43 			   (unsigned long) *outlen,
     44 			   (unsigned long) inlen);
     45 		return -1;
     46 	}
     47 
     48 	pos = out;
     49 	*pos++ = 0x00;
     50 	*pos++ = block_type; /* BT */
     51 	ps_len = modlen - inlen - 3;
     52 	switch (block_type) {
     53 	case 0:
     54 		os_memset(pos, 0x00, ps_len);
     55 		pos += ps_len;
     56 		break;
     57 	case 1:
     58 		os_memset(pos, 0xff, ps_len);
     59 		pos += ps_len;
     60 		break;
     61 	case 2:
     62 		if (os_get_random(pos, ps_len) < 0) {
     63 			wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get "
     64 				   "random data for PS", __func__);
     65 			return -1;
     66 		}
     67 		while (ps_len--) {
     68 			if (*pos == 0x00)
     69 				*pos = 0x01;
     70 			pos++;
     71 		}
     72 		break;
     73 	default:
     74 		wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type "
     75 			   "%d", __func__, block_type);
     76 		return -1;
     77 	}
     78 	*pos++ = 0x00;
     79 	os_memcpy(pos, in, inlen); /* D */
     80 
     81 	return 0;
     82 }
     83 
     84 
     85 int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key,
     86 		  int use_private, const u8 *in, size_t inlen,
     87 		  u8 *out, size_t *outlen)
     88 {
     89 	size_t modlen;
     90 
     91 	modlen = crypto_rsa_get_modulus_len(key);
     92 
     93 	if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen,
     94 					    out, outlen) < 0)
     95 		return -1;
     96 
     97 	return crypto_rsa_exptmod(out, modlen, out, outlen, key, use_private);
     98 }
     99 
    100 
    101 int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key,
    102 				  const u8 *in, size_t inlen,
    103 				  u8 *out, size_t *outlen)
    104 {
    105 	int res;
    106 	u8 *pos, *end;
    107 
    108 	res = crypto_rsa_exptmod(in, inlen, out, outlen, key, 1);
    109 	if (res)
    110 		return res;
    111 
    112 	if (*outlen < 2 || out[0] != 0 || out[1] != 2)
    113 		return -1;
    114 
    115 	/* Skip PS (pseudorandom non-zero octets) */
    116 	pos = out + 2;
    117 	end = out + *outlen;
    118 	while (*pos && pos < end)
    119 		pos++;
    120 	if (pos == end)
    121 		return -1;
    122 	pos++;
    123 
    124 	*outlen -= pos - out;
    125 
    126 	/* Strip PKCS #1 header */
    127 	os_memmove(out, pos, *outlen);
    128 
    129 	return 0;
    130 }
    131 
    132 
    133 int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
    134 			     const u8 *crypt, size_t crypt_len,
    135 			     u8 *plain, size_t *plain_len)
    136 {
    137 	size_t len;
    138 	u8 *pos;
    139 
    140 	len = *plain_len;
    141 	if (crypto_rsa_exptmod(crypt, crypt_len, plain, &len, key, 0) < 0)
    142 		return -1;
    143 
    144 	/*
    145 	 * PKCS #1 v1.5, 8.1:
    146 	 *
    147 	 * EB = 00 || BT || PS || 00 || D
    148 	 * BT = 00 or 01
    149 	 * PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01)
    150 	 * k = length of modulus in octets
    151 	 */
    152 
    153 	if (len < 3 + 8 + 16 /* min hash len */ ||
    154 	    plain[0] != 0x00 || (plain[1] != 0x00 && plain[1] != 0x01)) {
    155 		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
    156 			   "structure");
    157 		return -1;
    158 	}
    159 
    160 	pos = plain + 3;
    161 	if (plain[1] == 0x00) {
    162 		/* BT = 00 */
    163 		if (plain[2] != 0x00) {
    164 			wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
    165 				   "PS (BT=00)");
    166 			return -1;
    167 		}
    168 		while (pos + 1 < plain + len && *pos == 0x00 && pos[1] == 0x00)
    169 			pos++;
    170 	} else {
    171 		/* BT = 01 */
    172 		if (plain[2] != 0xff) {
    173 			wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
    174 				   "PS (BT=01)");
    175 			return -1;
    176 		}
    177 		while (pos < plain + len && *pos == 0xff)
    178 			pos++;
    179 	}
    180 
    181 	if (pos - plain - 2 < 8) {
    182 		/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
    183 		wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
    184 			   "padding");
    185 		return -1;
    186 	}
    187 
    188 	if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
    189 		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
    190 			   "structure (2)");
    191 		return -1;
    192 	}
    193 	pos++;
    194 	len -= pos - plain;
    195 
    196 	/* Strip PKCS #1 header */
    197 	os_memmove(plain, pos, len);
    198 	*plain_len = len;
    199 
    200 	return 0;
    201 }
    202