All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto Maven / Gradle / Ivy

There is a newer version: 1.0.7
Show newest version
package org.bouncycastle.tls.crypto.impl.jcajce;

import java.io.IOException;
import java.math.BigInteger;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Hashtable;
import java.util.Vector;

import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;

import org.bouncycastle.jcajce.util.JcaJceHelper;
import org.bouncycastle.jcajce.util.ProviderJcaJceHelper;
import org.bouncycastle.tls.AlertDescription;
import org.bouncycastle.tls.CertificateType;
import org.bouncycastle.tls.DigitallySigned;
import org.bouncycastle.tls.EncryptionAlgorithm;
import org.bouncycastle.tls.HashAlgorithm;
import org.bouncycastle.tls.MACAlgorithm;
import org.bouncycastle.tls.NamedGroup;
import org.bouncycastle.tls.ProtocolVersion;
import org.bouncycastle.tls.SignatureAlgorithm;
import org.bouncycastle.tls.SignatureAndHashAlgorithm;
import org.bouncycastle.tls.SignatureScheme;
import org.bouncycastle.tls.TlsDHUtils;
import org.bouncycastle.tls.TlsFatalAlert;
import org.bouncycastle.tls.TlsUtils;
import org.bouncycastle.tls.crypto.CryptoHashAlgorithm;
import org.bouncycastle.tls.crypto.CryptoSignatureAlgorithm;
import org.bouncycastle.tls.crypto.SRP6Group;
import org.bouncycastle.tls.crypto.Tls13Verifier;
import org.bouncycastle.tls.crypto.TlsCertificate;
import org.bouncycastle.tls.crypto.TlsCipher;
import org.bouncycastle.tls.crypto.TlsCryptoException;
import org.bouncycastle.tls.crypto.TlsCryptoParameters;
import org.bouncycastle.tls.crypto.TlsCryptoUtils;
import org.bouncycastle.tls.crypto.TlsDHConfig;
import org.bouncycastle.tls.crypto.TlsDHDomain;
import org.bouncycastle.tls.crypto.TlsECConfig;
import org.bouncycastle.tls.crypto.TlsECDomain;
import org.bouncycastle.tls.crypto.TlsHMAC;
import org.bouncycastle.tls.crypto.TlsHash;
import org.bouncycastle.tls.crypto.TlsKemConfig;
import org.bouncycastle.tls.crypto.TlsKemDomain;
import org.bouncycastle.tls.crypto.TlsNonceGenerator;
import org.bouncycastle.tls.crypto.TlsSRP6Client;
import org.bouncycastle.tls.crypto.TlsSRP6Server;
import org.bouncycastle.tls.crypto.TlsSRP6VerifierGenerator;
import org.bouncycastle.tls.crypto.TlsSRPConfig;
import org.bouncycastle.tls.crypto.TlsSecret;
import org.bouncycastle.tls.crypto.TlsStreamSigner;
import org.bouncycastle.tls.crypto.TlsStreamVerifier;
import org.bouncycastle.tls.crypto.impl.AbstractTlsCrypto;
import org.bouncycastle.tls.crypto.impl.TlsAEADCipher;
import org.bouncycastle.tls.crypto.impl.TlsAEADCipherImpl;
import org.bouncycastle.tls.crypto.impl.TlsBlockCipher;
import org.bouncycastle.tls.crypto.impl.TlsBlockCipherImpl;
import org.bouncycastle.tls.crypto.impl.TlsImplUtils;
import org.bouncycastle.tls.crypto.impl.TlsNullCipher;
import org.bouncycastle.tls.crypto.impl.jcajce.srp.SRP6Client;
import org.bouncycastle.tls.crypto.impl.jcajce.srp.SRP6Server;
import org.bouncycastle.tls.crypto.impl.jcajce.srp.SRP6VerifierGenerator;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Integers;
import org.bouncycastle.util.Strings;

/**
 * Class for providing cryptographic services for TLS based on implementations in the JCA/JCE.
 * 

* This class provides default implementations for everything. If you need to customise it, extend the class * and override the appropriate methods. *

*/ public class JcaTlsCrypto extends AbstractTlsCrypto { private final JcaJceHelper helper; private final SecureRandom entropySource; private final SecureRandom nonceEntropySource; private final Hashtable supportedEncryptionAlgorithms = new Hashtable(); private final Hashtable supportedNamedGroups = new Hashtable(); private final Hashtable supportedOther = new Hashtable(); /** * Base constructor. * * @param helper a JCA/JCE helper configured for the class's default provider. * @param entropySource primary entropy source, used for key generation. * @param nonceEntropySource secondary entropy source, used for nonce and IV generation. */ protected JcaTlsCrypto(JcaJceHelper helper, SecureRandom entropySource, SecureRandom nonceEntropySource) { this.helper = helper; this.entropySource = entropySource; this.nonceEntropySource = nonceEntropySource; } JceTlsSecret adoptLocalSecret(byte[] data) { return new JceTlsSecret(this, data); } Cipher createRSAEncryptionCipher() throws GeneralSecurityException { try { return getHelper().createCipher("RSA/NONE/PKCS1Padding"); } catch (GeneralSecurityException e) { return getHelper().createCipher("RSA/ECB/PKCS1Padding"); // try old style } } public TlsNonceGenerator createNonceGenerator(byte[] additionalSeedMaterial) { return new JcaNonceGenerator(nonceEntropySource, additionalSeedMaterial); } public SecureRandom getSecureRandom() { return entropySource; } public byte[] calculateKeyAgreement(String agreementAlgorithm, PrivateKey privateKey, PublicKey publicKey, String secretAlgorithm) throws GeneralSecurityException { KeyAgreement agreement = helper.createKeyAgreement(agreementAlgorithm); agreement.init(privateKey); agreement.doPhase(publicKey, true); try { return agreement.generateSecret(secretAlgorithm).getEncoded(); } catch (NoSuchAlgorithmException e) { // Oracle provider currently does not support generateSecret(algorithmName) for these. if ("X25519".equals(agreementAlgorithm) || "X448".equals(agreementAlgorithm)) { return agreement.generateSecret(); } throw e; } } public TlsCertificate createCertificate(byte[] encoding) throws IOException { return createCertificate(CertificateType.X509, encoding); } public TlsCertificate createCertificate(short type, byte[] encoding) throws IOException { if (type != CertificateType.X509) { throw new TlsFatalAlert(AlertDescription.unsupported_certificate); } return new JcaTlsCertificate(this, encoding); } public TlsCipher createCipher(TlsCryptoParameters cryptoParams, int encryptionAlgorithm, int macAlgorithm) throws IOException { try { switch (encryptionAlgorithm) { case EncryptionAlgorithm._3DES_EDE_CBC: return createCipher_CBC(cryptoParams, "DESede", 24, macAlgorithm); case EncryptionAlgorithm.AES_128_CBC: return createCipher_CBC(cryptoParams, "AES", 16, macAlgorithm); case EncryptionAlgorithm.AES_128_CCM: // NOTE: Ignores macAlgorithm return createCipher_AES_CCM(cryptoParams, 16, 16); case EncryptionAlgorithm.AES_128_CCM_8: // NOTE: Ignores macAlgorithm return createCipher_AES_CCM(cryptoParams, 16, 8); case EncryptionAlgorithm.AES_128_GCM: // NOTE: Ignores macAlgorithm return createCipher_AES_GCM(cryptoParams, 16, 16); case EncryptionAlgorithm.AES_256_CBC: return createCipher_CBC(cryptoParams, "AES", 32, macAlgorithm); case EncryptionAlgorithm.AES_256_CCM: // NOTE: Ignores macAlgorithm return createCipher_AES_CCM(cryptoParams, 32, 16); case EncryptionAlgorithm.AES_256_CCM_8: // NOTE: Ignores macAlgorithm return createCipher_AES_CCM(cryptoParams, 32, 8); case EncryptionAlgorithm.AES_256_GCM: // NOTE: Ignores macAlgorithm return createCipher_AES_GCM(cryptoParams, 32, 16); case EncryptionAlgorithm.ARIA_128_CBC: return createCipher_CBC(cryptoParams, "ARIA", 16, macAlgorithm); case EncryptionAlgorithm.ARIA_128_GCM: // NOTE: Ignores macAlgorithm return createCipher_ARIA_GCM(cryptoParams, 16, 16); case EncryptionAlgorithm.ARIA_256_CBC: return createCipher_CBC(cryptoParams, "ARIA", 32, macAlgorithm); case EncryptionAlgorithm.ARIA_256_GCM: // NOTE: Ignores macAlgorithm return createCipher_ARIA_GCM(cryptoParams, 32, 16); case EncryptionAlgorithm.CAMELLIA_128_CBC: return createCipher_CBC(cryptoParams, "Camellia", 16, macAlgorithm); case EncryptionAlgorithm.CAMELLIA_128_GCM: // NOTE: Ignores macAlgorithm return createCipher_Camellia_GCM(cryptoParams, 16, 16); case EncryptionAlgorithm.CAMELLIA_256_CBC: return createCipher_CBC(cryptoParams, "Camellia", 32, macAlgorithm); case EncryptionAlgorithm.CAMELLIA_256_GCM: // NOTE: Ignores macAlgorithm return createCipher_Camellia_GCM(cryptoParams, 32, 16); case EncryptionAlgorithm.CHACHA20_POLY1305: // NOTE: Ignores macAlgorithm return createChaCha20Poly1305(cryptoParams); case EncryptionAlgorithm.NULL: return createNullCipher(cryptoParams, macAlgorithm); case EncryptionAlgorithm.SEED_CBC: return createCipher_CBC(cryptoParams, "SEED", 16, macAlgorithm); case EncryptionAlgorithm.SM4_CBC: return createCipher_CBC(cryptoParams, "SM4", 16, macAlgorithm); case EncryptionAlgorithm.SM4_CCM: // NOTE: Ignores macAlgorithm return createCipher_SM4_CCM(cryptoParams); case EncryptionAlgorithm.SM4_GCM: // NOTE: Ignores macAlgorithm return createCipher_SM4_GCM(cryptoParams); case EncryptionAlgorithm._28147_CNT_IMIT: case EncryptionAlgorithm.DES40_CBC: case EncryptionAlgorithm.DES_CBC: case EncryptionAlgorithm.IDEA_CBC: case EncryptionAlgorithm.KUZNYECHIK_CTR_OMAC: case EncryptionAlgorithm.MAGMA_CTR_OMAC: case EncryptionAlgorithm.RC2_CBC_40: case EncryptionAlgorithm.RC4_128: case EncryptionAlgorithm.RC4_40: default: throw new TlsFatalAlert(AlertDescription.internal_error); } } catch (GeneralSecurityException e) { throw new TlsCryptoException("cannot create cipher: " + e.getMessage(), e); } } public TlsHMAC createHMAC(int macAlgorithm) { switch (macAlgorithm) { case MACAlgorithm.hmac_md5: case MACAlgorithm.hmac_sha1: case MACAlgorithm.hmac_sha256: case MACAlgorithm.hmac_sha384: case MACAlgorithm.hmac_sha512: return createHMACForHash(TlsCryptoUtils.getHashForHMAC(macAlgorithm)); default: throw new IllegalArgumentException("invalid MACAlgorithm: " + macAlgorithm); } } public TlsHMAC createHMACForHash(int cryptoHashAlgorithm) { String hmacName = getHMACAlgorithmName(cryptoHashAlgorithm); try { return new JceTlsHMAC(cryptoHashAlgorithm, helper.createMac(hmacName), hmacName); } catch (GeneralSecurityException e) { throw new RuntimeException("cannot create HMAC: " + hmacName, e); } } protected TlsHMAC createHMAC_SSL(int macAlgorithm) throws GeneralSecurityException, IOException { switch (macAlgorithm) { case MACAlgorithm.hmac_md5: return new JcaSSL3HMAC(createHash(getDigestName(CryptoHashAlgorithm.md5)), 16, 64); case MACAlgorithm.hmac_sha1: return new JcaSSL3HMAC(createHash(getDigestName(CryptoHashAlgorithm.sha1)), 20, 64); case MACAlgorithm.hmac_sha256: return new JcaSSL3HMAC(createHash(getDigestName(CryptoHashAlgorithm.sha256)), 32, 64); case MACAlgorithm.hmac_sha384: return new JcaSSL3HMAC(createHash(getDigestName(CryptoHashAlgorithm.sha384)), 48, 128); case MACAlgorithm.hmac_sha512: return new JcaSSL3HMAC(createHash(getDigestName(CryptoHashAlgorithm.sha512)), 64, 128); default: throw new TlsFatalAlert(AlertDescription.internal_error); } } protected TlsHMAC createMAC(TlsCryptoParameters cryptoParams, int macAlgorithm) throws GeneralSecurityException, IOException { if (TlsImplUtils.isSSL(cryptoParams)) { return createHMAC_SSL(macAlgorithm); } else { return createHMAC(macAlgorithm); } } public TlsSRP6Client createSRP6Client(TlsSRPConfig srpConfig) { final SRP6Client srpClient = new SRP6Client(); BigInteger[] ng = srpConfig.getExplicitNG(); SRP6Group srpGroup= new SRP6Group(ng[0], ng[1]); srpClient.init(srpGroup, createHash(CryptoHashAlgorithm.sha1), this.getSecureRandom()); return new TlsSRP6Client() { public BigInteger calculateSecret(BigInteger serverB) throws TlsFatalAlert { try { return srpClient.calculateSecret(serverB); } catch (IllegalArgumentException e) { throw new TlsFatalAlert(AlertDescription.illegal_parameter, e); } } public BigInteger generateClientCredentials(byte[] srpSalt, byte[] identity, byte[] password) { return srpClient.generateClientCredentials(srpSalt, identity, password); } }; } public TlsSRP6Server createSRP6Server(TlsSRPConfig srpConfig, BigInteger srpVerifier) { final SRP6Server srpServer = new SRP6Server(); BigInteger[] ng = srpConfig.getExplicitNG(); SRP6Group srpGroup= new SRP6Group(ng[0], ng[1]); srpServer.init(srpGroup, srpVerifier, createHash(CryptoHashAlgorithm.sha1), this.getSecureRandom()); return new TlsSRP6Server() { public BigInteger generateServerCredentials() { return srpServer.generateServerCredentials(); } public BigInteger calculateSecret(BigInteger clientA) throws IOException { try { return srpServer.calculateSecret(clientA); } catch (IllegalArgumentException e) { throw new TlsFatalAlert(AlertDescription.illegal_parameter, e); } } }; } public TlsSRP6VerifierGenerator createSRP6VerifierGenerator(TlsSRPConfig srpConfig) { BigInteger[] ng = srpConfig.getExplicitNG(); final SRP6VerifierGenerator verifierGenerator = new SRP6VerifierGenerator(); verifierGenerator.init(ng[0], ng[1], createHash(CryptoHashAlgorithm.sha1)); return new TlsSRP6VerifierGenerator() { public BigInteger generateVerifier(byte[] salt, byte[] identity, byte[] password) { return verifierGenerator.generateVerifier(salt, identity, password); } }; } String getHMACAlgorithmName(int cryptoHashAlgorithm) { switch (cryptoHashAlgorithm) { case CryptoHashAlgorithm.md5: return "HmacMD5"; case CryptoHashAlgorithm.sha1: return "HmacSHA1"; case CryptoHashAlgorithm.sha224: return "HmacSHA224"; case CryptoHashAlgorithm.sha256: return "HmacSHA256"; case CryptoHashAlgorithm.sha384: return "HmacSHA384"; case CryptoHashAlgorithm.sha512: return "HmacSHA512"; case CryptoHashAlgorithm.sm3: return "HmacSM3"; case CryptoHashAlgorithm.gostr3411_2012_256: return "HmacGOST3411-2012-256"; default: throw new IllegalArgumentException("invalid CryptoHashAlgorithm: " + cryptoHashAlgorithm); } } public AlgorithmParameters getNamedGroupAlgorithmParameters(int namedGroup) throws GeneralSecurityException { if (NamedGroup.refersToAnXDHCurve(namedGroup)) { switch (namedGroup) { /* * TODO Return AlgorithmParameters to check against disabled algorithms * * NOTE: The JDK doesn't even support AlgorithmParameters for XDH, so SunJSSE also winds * up using null AlgorithmParameters when checking algorithm constraints. */ case NamedGroup.x25519: case NamedGroup.x448: return null; } } else if (NamedGroup.refersToAnECDSACurve(namedGroup)) { return ECUtil.getAlgorithmParameters(this, NamedGroup.getCurveName(namedGroup)); } else if (NamedGroup.refersToASpecificFiniteField(namedGroup)) { return DHUtil.getAlgorithmParameters(this, TlsDHUtils.getNamedDHGroup(namedGroup)); } else if (NamedGroup.refersToASpecificKem(namedGroup)) { switch (namedGroup) { /* * TODO[tls-kem] Return AlgorithmParameters to check against disabled algorithms? */ case NamedGroup.OQS_mlkem512: case NamedGroup.OQS_mlkem768: case NamedGroup.OQS_mlkem1024: case NamedGroup.DRAFT_mlkem768: case NamedGroup.DRAFT_mlkem1024: return null; } } throw new IllegalArgumentException("NamedGroup not supported: " + NamedGroup.getText(namedGroup)); } public AlgorithmParameters getSignatureSchemeAlgorithmParameters(int signatureScheme) throws GeneralSecurityException { if (!SignatureScheme.isRSAPSS(signatureScheme)) { return null; } int cryptoHashAlgorithm = SignatureScheme.getCryptoHashAlgorithm(signatureScheme); if (cryptoHashAlgorithm < 0) { return null; } String digestName = getDigestName(cryptoHashAlgorithm); String sigName = RSAUtil.getDigestSigAlgName(digestName) + "WITHRSAANDMGF1"; AlgorithmParameterSpec pssSpec = RSAUtil.getPSSParameterSpec(cryptoHashAlgorithm, digestName, getHelper()); Signature signer = getHelper().createSignature(sigName); // NOTE: We explicitly set them even though they should be the defaults, because providers vary signer.setParameter(pssSpec); return signer.getParameters(); } public boolean hasAnyStreamVerifiers(Vector signatureAndHashAlgorithms) { boolean isRSAStreamVerifier = JcaUtils.isSunMSCAPIProviderActive(); for (int i = 0, count = signatureAndHashAlgorithms.size(); i < count; ++i) { SignatureAndHashAlgorithm algorithm = (SignatureAndHashAlgorithm)signatureAndHashAlgorithms.elementAt(i); switch (algorithm.getSignature()) { case SignatureAlgorithm.rsa: { if (isRSAStreamVerifier) { return true; } break; } case SignatureAlgorithm.dsa: { if (HashAlgorithm.getOutputSize(algorithm.getHash()) != 20) { return true; } break; } } switch (SignatureScheme.from(algorithm)) { case SignatureScheme.ed25519: case SignatureScheme.ed448: case SignatureScheme.rsa_pss_rsae_sha256: case SignatureScheme.rsa_pss_rsae_sha384: case SignatureScheme.rsa_pss_rsae_sha512: case SignatureScheme.rsa_pss_pss_sha256: case SignatureScheme.rsa_pss_pss_sha384: case SignatureScheme.rsa_pss_pss_sha512: return true; } } return false; } public boolean hasAnyStreamVerifiersLegacy(short[] clientCertificateTypes) { return false; } public boolean hasCryptoHashAlgorithm(int cryptoHashAlgorithm) { // TODO: expand return true; } public boolean hasCryptoSignatureAlgorithm(int cryptoSignatureAlgorithm) { switch (cryptoSignatureAlgorithm) { case CryptoSignatureAlgorithm.rsa: case CryptoSignatureAlgorithm.dsa: case CryptoSignatureAlgorithm.ecdsa: case CryptoSignatureAlgorithm.rsa_pss_rsae_sha256: case CryptoSignatureAlgorithm.rsa_pss_rsae_sha384: case CryptoSignatureAlgorithm.rsa_pss_rsae_sha512: case CryptoSignatureAlgorithm.ed25519: case CryptoSignatureAlgorithm.ed448: case CryptoSignatureAlgorithm.rsa_pss_pss_sha256: case CryptoSignatureAlgorithm.rsa_pss_pss_sha384: case CryptoSignatureAlgorithm.rsa_pss_pss_sha512: return true; // TODO[RFC 9189] case CryptoSignatureAlgorithm.gostr34102012_256: case CryptoSignatureAlgorithm.gostr34102012_512: // TODO[RFC 8998] case CryptoSignatureAlgorithm.sm2: default: return false; } } public boolean hasDHAgreement() { return true; } public boolean hasECDHAgreement() { return true; } public boolean hasKemAgreement() { return true; } public boolean hasEncryptionAlgorithm(int encryptionAlgorithm) { final Integer key = Integers.valueOf(encryptionAlgorithm); synchronized (supportedEncryptionAlgorithms) { Boolean cached = (Boolean)supportedEncryptionAlgorithms.get(key); if (cached != null) { return cached.booleanValue(); } } Boolean supported = isSupportedEncryptionAlgorithm(encryptionAlgorithm); if (null == supported) { return false; } synchronized (supportedEncryptionAlgorithms) { Boolean cached = (Boolean)supportedEncryptionAlgorithms.put(key, supported); // Unlikely, but we want a consistent result if (null != cached && supported != cached) { supportedEncryptionAlgorithms.put(key, cached); supported = cached; } } return supported.booleanValue(); } public boolean hasHKDFAlgorithm(int cryptoHashAlgorithm) { switch (cryptoHashAlgorithm) { case CryptoHashAlgorithm.sha256: case CryptoHashAlgorithm.sha384: case CryptoHashAlgorithm.sha512: case CryptoHashAlgorithm.sm3: return true; default: return false; } } public boolean hasMacAlgorithm(int macAlgorithm) { switch (macAlgorithm) { case MACAlgorithm.hmac_md5: case MACAlgorithm.hmac_sha1: case MACAlgorithm.hmac_sha256: case MACAlgorithm.hmac_sha384: case MACAlgorithm.hmac_sha512: return true; default: return false; } } public boolean hasNamedGroup(int namedGroup) { final Integer key = Integers.valueOf(namedGroup); synchronized (supportedNamedGroups) { Boolean cached = (Boolean)supportedNamedGroups.get(key); if (null != cached) { return cached.booleanValue(); } } Boolean supported = isSupportedNamedGroup(namedGroup); if (null == supported) { return false; } synchronized (supportedNamedGroups) { Boolean cached = (Boolean)supportedNamedGroups.put(key, supported); // Unlikely, but we want a consistent result if (null != cached && supported != cached) { supportedNamedGroups.put(key, cached); supported = cached; } } return supported.booleanValue(); } public boolean hasRSAEncryption() { final String key = "KE_RSA"; synchronized (supportedOther) { Boolean cached = (Boolean)supportedOther.get(key); if (cached != null) { return cached.booleanValue(); } } Boolean supported; try { createRSAEncryptionCipher(); supported = Boolean.TRUE; } catch (GeneralSecurityException e) { supported = Boolean.FALSE; } synchronized (supportedOther) { Boolean cached = (Boolean)supportedOther.put(key, supported); // Unlikely, but we want a consistent result if (null != cached && supported != cached) { supportedOther.put(key, cached); supported = cached; } } return supported.booleanValue(); } public boolean hasSignatureAlgorithm(short signatureAlgorithm) { switch (signatureAlgorithm) { case SignatureAlgorithm.rsa: case SignatureAlgorithm.dsa: case SignatureAlgorithm.ecdsa: case SignatureAlgorithm.ed25519: case SignatureAlgorithm.ed448: case SignatureAlgorithm.rsa_pss_rsae_sha256: case SignatureAlgorithm.rsa_pss_rsae_sha384: case SignatureAlgorithm.rsa_pss_rsae_sha512: case SignatureAlgorithm.rsa_pss_pss_sha256: case SignatureAlgorithm.rsa_pss_pss_sha384: case SignatureAlgorithm.rsa_pss_pss_sha512: case SignatureAlgorithm.ecdsa_brainpoolP256r1tls13_sha256: case SignatureAlgorithm.ecdsa_brainpoolP384r1tls13_sha384: case SignatureAlgorithm.ecdsa_brainpoolP512r1tls13_sha512: return true; // TODO[RFC 9189] case SignatureAlgorithm.gostr34102012_256: case SignatureAlgorithm.gostr34102012_512: // TODO[RFC 8998] // case SignatureAlgorithm.sm2: default: return false; } } public boolean hasSignatureAndHashAlgorithm(SignatureAndHashAlgorithm sigAndHashAlgorithm) { short signature = sigAndHashAlgorithm.getSignature(); switch (sigAndHashAlgorithm.getHash()) { case HashAlgorithm.md5: return SignatureAlgorithm.rsa == signature && hasSignatureAlgorithm(signature); case HashAlgorithm.sha224: // Somewhat overkill, but simpler for now. It's also consistent with SunJSSE behaviour. return !JcaUtils.isSunMSCAPIProviderActive() && hasSignatureAlgorithm(signature); default: return hasSignatureAlgorithm(signature); } } public boolean hasSignatureScheme(int signatureScheme) { switch (signatureScheme) { case SignatureScheme.sm2sig_sm3: return false; default: { short signature = SignatureScheme.getSignatureAlgorithm(signatureScheme); switch(SignatureScheme.getCryptoHashAlgorithm(signatureScheme)) { case CryptoHashAlgorithm.md5: return SignatureAlgorithm.rsa == signature && hasSignatureAlgorithm(signature); case CryptoHashAlgorithm.sha224: // Somewhat overkill, but simpler for now. It's also consistent with SunJSSE behaviour. return !JcaUtils.isSunMSCAPIProviderActive() && hasSignatureAlgorithm(signature); default: return hasSignatureAlgorithm(signature); } } } } public boolean hasSRPAuthentication() { return true; } public TlsSecret createSecret(byte[] data) { try { return adoptLocalSecret(Arrays.clone(data)); } finally { // TODO[tls-ops] Add this after checking all callers // if (data != null) // { // Arrays.fill(data, (byte)0); // } } } public TlsSecret generateRSAPreMasterSecret(ProtocolVersion version) { byte[] data = new byte[48]; getSecureRandom().nextBytes(data); TlsUtils.writeVersion(version, data, 0); return adoptLocalSecret(data); } public TlsHash createHash(int cryptoHashAlgorithm) { try { return createHash(getDigestName(cryptoHashAlgorithm)); } catch (GeneralSecurityException e) { throw Exceptions.illegalArgumentException("unable to create message digest:" + e.getMessage(), e); } } public TlsDHDomain createDHDomain(TlsDHConfig dhConfig) { return new JceTlsDHDomain(this, dhConfig); } public TlsECDomain createECDomain(TlsECConfig ecConfig) { switch (ecConfig.getNamedGroup()) { case NamedGroup.x25519: return new JceX25519Domain(this); case NamedGroup.x448: return new JceX448Domain(this); default: return new JceTlsECDomain(this, ecConfig); } } public TlsKemDomain createKemDomain(TlsKemConfig kemConfig) { return new JceTlsMLKemDomain(this, kemConfig); } public TlsSecret hkdfInit(int cryptoHashAlgorithm) { return adoptLocalSecret(new byte[TlsCryptoUtils.getHashOutputSize(cryptoHashAlgorithm)]); } /** * If you want to create your own versions of the AEAD ciphers required, override this method. * * @param cipherName the full name of the cipher (algorithm/mode/padding) * @param algorithm the base algorithm name * @param keySize keySize (in bytes) for the cipher key. * @param isEncrypting true if the cipher is for encryption, false otherwise. * @return an AEAD cipher. * @throws GeneralSecurityException in case of failure. */ protected TlsAEADCipherImpl createAEADCipher(String cipherName, String algorithm, int keySize, boolean isEncrypting) throws GeneralSecurityException { return new JceAEADCipherImpl(this, helper, cipherName, algorithm, keySize, isEncrypting); } /** * If you want to create your own versions of the block ciphers required, override this method. * * @param cipherName the full name of the cipher (algorithm/mode/padding) * @param algorithm the base algorithm name * @param keySize keySize (in bytes) for the cipher key. * @param isEncrypting true if the cipher is for encryption, false otherwise. * @return a block cipher. * @throws GeneralSecurityException in case of failure. */ protected TlsBlockCipherImpl createBlockCipher(String cipherName, String algorithm, int keySize, boolean isEncrypting) throws GeneralSecurityException { return new JceBlockCipherImpl(this, helper.createCipher(cipherName), algorithm, keySize, isEncrypting); } /** * If you want to create your own versions of the block ciphers for < TLS 1.1, override this method. * * @param cipherName the full name of the cipher (algorithm/mode/padding) * @param algorithm the base algorithm name * @param keySize keySize (in bytes) for the cipher key. * @param isEncrypting true if the cipher is for encryption, false otherwise. * @return a block cipher. * @throws GeneralSecurityException in case of failure. */ protected TlsBlockCipherImpl createBlockCipherWithCBCImplicitIV(String cipherName, String algorithm, int keySize, boolean isEncrypting) throws GeneralSecurityException { return new JceBlockCipherWithCBCImplicitIVImpl(this, helper.createCipher(cipherName), algorithm, isEncrypting); } /** * If you want to create your own versions of Hash functions, override this method. * * @param digestName the name of the Hash function required. * @return a hash calculator. * @throws GeneralSecurityException in case of failure. */ protected TlsHash createHash(String digestName) throws GeneralSecurityException { return new JcaTlsHash(helper.createDigest(digestName)); } /** * To disable the null cipher suite, override this method with one that throws an IOException. * * @param macAlgorithm the name of the algorithm supporting the MAC. * @return a null cipher suite implementation. * @throws IOException in case of failure. * @throws GeneralSecurityException in case of a specific failure in the JCA/JCE layer. */ protected TlsNullCipher createNullCipher(TlsCryptoParameters cryptoParams, int macAlgorithm) throws IOException, GeneralSecurityException { return new TlsNullCipher(cryptoParams, createMAC(cryptoParams, macAlgorithm), createMAC(cryptoParams, macAlgorithm)); } protected TlsStreamSigner createStreamSigner(SignatureAndHashAlgorithm algorithm, PrivateKey privateKey, boolean needsRandom) throws IOException { String algorithmName = JcaUtils.getJcaAlgorithmName(algorithm); return createStreamSigner(algorithmName, null, privateKey, needsRandom); } protected TlsStreamSigner createStreamSigner(String algorithmName, AlgorithmParameterSpec parameter, PrivateKey privateKey, boolean needsRandom) throws IOException { try { SecureRandom random = needsRandom ? getSecureRandom() : null; JcaJceHelper helper = getHelper(); try { if (null != parameter) { Signature dummySigner = helper.createSignature(algorithmName); dummySigner.initSign(privateKey, random); helper = new ProviderJcaJceHelper(dummySigner.getProvider()); } Signature signer = helper.createSignature(algorithmName); if (null != parameter) { signer.setParameter(parameter); } signer.initSign(privateKey, random); return new JcaTlsStreamSigner(signer); } catch (InvalidKeyException e) { String upperAlg = Strings.toUpperCase(algorithmName); if (upperAlg.endsWith("MGF1")) { // ANDMGF1 has vanished from the Sun PKCS11 provider. algorithmName = upperAlg.replace("ANDMGF1", "SSA-PSS"); return createStreamSigner(algorithmName, parameter, privateKey, needsRandom); } else { throw e; } } } catch (GeneralSecurityException e) { throw new TlsFatalAlert(AlertDescription.internal_error, e); } } protected TlsStreamVerifier createStreamVerifier(DigitallySigned digitallySigned, PublicKey publicKey) throws IOException { String algorithmName = JcaUtils.getJcaAlgorithmName(digitallySigned.getAlgorithm()); return createStreamVerifier(algorithmName, null, digitallySigned.getSignature(), publicKey); } protected TlsStreamVerifier createStreamVerifier(String algorithmName, AlgorithmParameterSpec parameter, byte[] signature, PublicKey publicKey) throws IOException { try { JcaJceHelper helper = getHelper(); if (null != parameter) { Signature dummyVerifier = helper.createSignature(algorithmName); dummyVerifier.initVerify(publicKey); helper = new ProviderJcaJceHelper(dummyVerifier.getProvider()); } Signature verifier = helper.createSignature(algorithmName); if (null != parameter) { verifier.setParameter(parameter); } verifier.initVerify(publicKey); return new JcaTlsStreamVerifier(verifier, signature); } catch (GeneralSecurityException e) { throw new TlsFatalAlert(AlertDescription.internal_error, e); } } protected Tls13Verifier createTls13Verifier(String algorithmName, AlgorithmParameterSpec parameter, PublicKey publicKey) throws IOException { try { JcaJceHelper helper = getHelper(); if (null != parameter) { Signature dummyVerifier = helper.createSignature(algorithmName); dummyVerifier.initVerify(publicKey); helper = new ProviderJcaJceHelper(dummyVerifier.getProvider()); } Signature verifier = helper.createSignature(algorithmName); if (null != parameter) { verifier.setParameter(parameter); } verifier.initVerify(publicKey); return new JcaTls13Verifier(verifier); } catch (GeneralSecurityException e) { throw new TlsFatalAlert(AlertDescription.internal_error, e); } } protected TlsStreamSigner createVerifyingStreamSigner(SignatureAndHashAlgorithm algorithm, PrivateKey privateKey, boolean needsRandom, PublicKey publicKey) throws IOException { String algorithmName = JcaUtils.getJcaAlgorithmName(algorithm); return createVerifyingStreamSigner(algorithmName, null, privateKey, needsRandom, publicKey); } protected TlsStreamSigner createVerifyingStreamSigner(String algorithmName, AlgorithmParameterSpec parameter, PrivateKey privateKey, boolean needsRandom, PublicKey publicKey) throws IOException { try { Signature signer = getHelper().createSignature(algorithmName); Signature verifier = getHelper().createSignature(algorithmName); if (null != parameter) { signer.setParameter(parameter); verifier.setParameter(parameter); } signer.initSign(privateKey, needsRandom ? getSecureRandom() : null); verifier.initVerify(publicKey); return new JcaVerifyingStreamSigner(signer, verifier); } catch (GeneralSecurityException e) { throw new TlsFatalAlert(AlertDescription.internal_error, e); } } protected Boolean isSupportedEncryptionAlgorithm(int encryptionAlgorithm) { switch (encryptionAlgorithm) { case EncryptionAlgorithm._3DES_EDE_CBC: return isUsableCipher("DESede/CBC/NoPadding", 192); case EncryptionAlgorithm.AES_128_CBC: return isUsableCipher("AES/CBC/NoPadding", 128); case EncryptionAlgorithm.AES_128_CCM: case EncryptionAlgorithm.AES_128_CCM_8: return isUsableCipher("AES/CCM/NoPadding", 128); case EncryptionAlgorithm.AES_128_GCM: return isUsableCipher("AES/GCM/NoPadding", 128); case EncryptionAlgorithm.AES_256_CBC: return isUsableCipher("AES/CBC/NoPadding", 256); case EncryptionAlgorithm.AES_256_CCM: case EncryptionAlgorithm.AES_256_CCM_8: return isUsableCipher("AES/CCM/NoPadding", 256); case EncryptionAlgorithm.AES_256_GCM: return isUsableCipher("AES/GCM/NoPadding", 256); case EncryptionAlgorithm.ARIA_128_CBC: return isUsableCipher("ARIA/CBC/NoPadding", 128); case EncryptionAlgorithm.ARIA_128_GCM: return isUsableCipher("ARIA/GCM/NoPadding", 128); case EncryptionAlgorithm.ARIA_256_CBC: return isUsableCipher("ARIA/CBC/NoPadding", 256); case EncryptionAlgorithm.ARIA_256_GCM: return isUsableCipher("ARIA/GCM/NoPadding", 256); case EncryptionAlgorithm.CAMELLIA_128_CBC: return isUsableCipher("Camellia/CBC/NoPadding", 128); case EncryptionAlgorithm.CAMELLIA_128_GCM: return isUsableCipher("Camellia/GCM/NoPadding", 128); case EncryptionAlgorithm.CAMELLIA_256_CBC: return isUsableCipher("Camellia/CBC/NoPadding", 256); case EncryptionAlgorithm.CAMELLIA_256_GCM: return isUsableCipher("Camellia/GCM/NoPadding", 256); case EncryptionAlgorithm.CHACHA20_POLY1305: return isUsableCipher("ChaCha7539", 256) && isUsableMAC("Poly1305"); case EncryptionAlgorithm.NULL: return Boolean.TRUE; case EncryptionAlgorithm.SEED_CBC: return isUsableCipher("SEED/CBC/NoPadding", 128); case EncryptionAlgorithm.SM4_CBC: return isUsableCipher("SM4/CBC/NoPadding", 128); case EncryptionAlgorithm.SM4_CCM: return isUsableCipher("SM4/CCM/NoPadding", 128); case EncryptionAlgorithm.SM4_GCM: return isUsableCipher("SM4/GCM/NoPadding", 128); case EncryptionAlgorithm._28147_CNT_IMIT: case EncryptionAlgorithm.DES_CBC: case EncryptionAlgorithm.DES40_CBC: case EncryptionAlgorithm.IDEA_CBC: case EncryptionAlgorithm.KUZNYECHIK_CTR_OMAC: case EncryptionAlgorithm.MAGMA_CTR_OMAC: case EncryptionAlgorithm.RC2_CBC_40: case EncryptionAlgorithm.RC4_128: case EncryptionAlgorithm.RC4_40: return Boolean.FALSE; } return null; } protected Boolean isSupportedNamedGroup(int namedGroup) { try { if (NamedGroup.refersToAnXDHCurve(namedGroup)) { /* * NOTE: We don't check for AlgorithmParameters support because even the SunEC * provider doesn't support them. We skip checking KeyFactory and KeyPairGenerator * for performance reasons (and this is consistent with SunJSSE behaviour). */ switch (namedGroup) { case NamedGroup.x25519: { // helper.createAlgorithmParameters("X25519"); helper.createKeyAgreement("X25519"); // helper.createKeyFactory("X25519"); // helper.createKeyPairGenerator("X25519"); return Boolean.TRUE; } case NamedGroup.x448: { // helper.createAlgorithmParameters("X448"); helper.createKeyAgreement("X448"); // helper.createKeyFactory("X448"); // helper.createKeyPairGenerator("X448"); return Boolean.TRUE; } } } else if (NamedGroup.refersToASpecificKem(namedGroup)) { // TODO[tls-kem] When implemented via provider, need to check for support dynamically return Boolean.TRUE; } else if (NamedGroup.refersToAnECDSACurve(namedGroup)) { return Boolean.valueOf(ECUtil.isCurveSupported(this, NamedGroup.getCurveName(namedGroup))); } else if (NamedGroup.refersToASpecificFiniteField(namedGroup)) { return Boolean.valueOf(DHUtil.isGroupSupported(this, TlsDHUtils.getNamedDHGroup(namedGroup))); } } catch (GeneralSecurityException e) { return Boolean.FALSE; } // 'null' means we don't even recognize the NamedGroup return null; } protected boolean isUsableCipher(String cipherAlgorithm, int keySize) { try { helper.createCipher(cipherAlgorithm); return Cipher.getMaxAllowedKeyLength(cipherAlgorithm) >= keySize; } catch (GeneralSecurityException e) { return false; } } protected boolean isUsableMAC(String macAlgorithm) { try { helper.createMac(macAlgorithm); return true; } catch (GeneralSecurityException e) { return false; } } public JcaJceHelper getHelper() { return helper; } protected TlsBlockCipherImpl createCBCBlockCipherImpl(TlsCryptoParameters cryptoParams, String algorithm, int cipherKeySize, boolean forEncryption) throws GeneralSecurityException { String cipherName = algorithm + "/CBC/NoPadding"; if (TlsImplUtils.isTLSv11(cryptoParams)) { return createBlockCipher(cipherName, algorithm, cipherKeySize, forEncryption); } else { return createBlockCipherWithCBCImplicitIV(cipherName, algorithm, cipherKeySize, forEncryption); } } private TlsCipher createChaCha20Poly1305(TlsCryptoParameters cryptoParams) throws IOException, GeneralSecurityException { return new TlsAEADCipher(cryptoParams, new JceChaCha20Poly1305(this, helper, true), new JceChaCha20Poly1305(this, helper, false), 32, 16, TlsAEADCipher.AEAD_CHACHA20_POLY1305); } private TlsAEADCipher createCipher_AES_CCM(TlsCryptoParameters cryptoParams, int cipherKeySize, int macSize) throws IOException, GeneralSecurityException { return new TlsAEADCipher(cryptoParams, createAEADCipher("AES/CCM/NoPadding", "AES", cipherKeySize, true), createAEADCipher("AES/CCM/NoPadding", "AES", cipherKeySize, false), cipherKeySize, macSize, TlsAEADCipher.AEAD_CCM); } private TlsAEADCipher createCipher_AES_GCM(TlsCryptoParameters cryptoParams, int cipherKeySize, int macSize) throws IOException, GeneralSecurityException { return new TlsAEADCipher(cryptoParams, createAEADCipher("AES/GCM/NoPadding", "AES", cipherKeySize, true), createAEADCipher("AES/GCM/NoPadding", "AES", cipherKeySize, false), cipherKeySize, macSize, TlsAEADCipher.AEAD_GCM); } private TlsAEADCipher createCipher_ARIA_GCM(TlsCryptoParameters cryptoParams, int cipherKeySize, int macSize) throws IOException, GeneralSecurityException { return new TlsAEADCipher(cryptoParams, createAEADCipher("ARIA/GCM/NoPadding", "ARIA", cipherKeySize, true), createAEADCipher("ARIA/GCM/NoPadding", "ARIA", cipherKeySize, false), cipherKeySize, macSize, TlsAEADCipher.AEAD_GCM); } private TlsAEADCipher createCipher_Camellia_GCM(TlsCryptoParameters cryptoParams, int cipherKeySize, int macSize) throws IOException, GeneralSecurityException { return new TlsAEADCipher(cryptoParams, createAEADCipher("Camellia/GCM/NoPadding", "Camellia", cipherKeySize, true), createAEADCipher("Camellia/GCM/NoPadding", "Camellia", cipherKeySize, false), cipherKeySize, macSize, TlsAEADCipher.AEAD_GCM); } protected TlsCipher createCipher_CBC(TlsCryptoParameters cryptoParams, String algorithm, int cipherKeySize, int macAlgorithm) throws GeneralSecurityException, IOException { TlsBlockCipherImpl encrypt = createCBCBlockCipherImpl(cryptoParams, algorithm, cipherKeySize, true); TlsBlockCipherImpl decrypt = createCBCBlockCipherImpl(cryptoParams, algorithm, cipherKeySize, false); TlsHMAC clientMAC = createMAC(cryptoParams, macAlgorithm); TlsHMAC serverMAC = createMAC(cryptoParams, macAlgorithm); return new TlsBlockCipher(cryptoParams, encrypt, decrypt, clientMAC, serverMAC, cipherKeySize); } private TlsAEADCipher createCipher_SM4_CCM(TlsCryptoParameters cryptoParams) throws IOException, GeneralSecurityException { int cipherKeySize = 16, macSize = 16; return new TlsAEADCipher(cryptoParams, createAEADCipher("SM4/CCM/NoPadding", "SM4", cipherKeySize, true), createAEADCipher("SM4/CCM/NoPadding", "SM4", cipherKeySize, false), cipherKeySize, macSize, TlsAEADCipher.AEAD_CCM); } private TlsAEADCipher createCipher_SM4_GCM(TlsCryptoParameters cryptoParams) throws IOException, GeneralSecurityException { int cipherKeySize = 16, macSize = 16; return new TlsAEADCipher(cryptoParams, createAEADCipher("SM4/GCM/NoPadding", "SM4", cipherKeySize, true), createAEADCipher("SM4/GCM/NoPadding", "SM4", cipherKeySize, false), cipherKeySize, macSize, TlsAEADCipher.AEAD_GCM); } String getDigestName(int cryptoHashAlgorithm) { switch (cryptoHashAlgorithm) { case CryptoHashAlgorithm.md5: return "MD5"; case CryptoHashAlgorithm.sha1: return "SHA-1"; case CryptoHashAlgorithm.sha224: return "SHA-224"; case CryptoHashAlgorithm.sha256: return "SHA-256"; case CryptoHashAlgorithm.sha384: return "SHA-384"; case CryptoHashAlgorithm.sha512: return "SHA-512"; case CryptoHashAlgorithm.sm3: return "SM3"; case CryptoHashAlgorithm.gostr3411_2012_256: return "GOST3411-2012-256"; default: throw new IllegalArgumentException("invalid CryptoHashAlgorithm: " + cryptoHashAlgorithm); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy