Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ec/ECDSASignature.java
38830 views
/*1* Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.ec;2627import java.nio.ByteBuffer;2829import java.security.*;30import java.security.interfaces.*;31import java.security.spec.*;32import java.util.Optional;3334import sun.security.jca.JCAUtil;35import sun.security.util.*;36import static sun.security.ec.ECOperations.IntermediateValueException;3738/**39* ECDSA signature implementation. This class currently supports the40* following algorithm names:41*42* . "NONEwithECDSA"43* . "SHA1withECDSA"44* . "SHA224withECDSA"45* . "SHA256withECDSA"46* . "SHA384withECDSA"47* . "SHA512withECDSA"48*49* @since 1.750*/51abstract class ECDSASignature extends SignatureSpi {5253// message digest implementation we use54private final MessageDigest messageDigest;5556// supplied entropy57private SecureRandom random;5859// flag indicating whether the digest has been reset60private boolean needsReset;6162// private key, if initialized for signing63private ECPrivateKey privateKey;6465// public key, if initialized for verifying66private ECPublicKey publicKey;6768// signature parameters69private ECParameterSpec sigParams = null;7071/**72* Constructs a new ECDSASignature. Used by Raw subclass.73*74* @exception ProviderException if the native ECC library is unavailable.75*/76ECDSASignature() {77messageDigest = null;78}7980/**81* Constructs a new ECDSASignature. Used by subclasses.82*/83ECDSASignature(String digestName) {84try {85messageDigest = MessageDigest.getInstance(digestName);86} catch (NoSuchAlgorithmException e) {87throw new ProviderException(e);88}89needsReset = false;90}9192// Nested class for NONEwithECDSA signatures93public static final class Raw extends ECDSASignature {9495// the longest supported digest is 512 bits (SHA-512)96private static final int RAW_ECDSA_MAX = 64;9798private final byte[] precomputedDigest;99private int offset = 0;100101public Raw() {102precomputedDigest = new byte[RAW_ECDSA_MAX];103}104105// Stores the precomputed message digest value.106@Override107protected void engineUpdate(byte b) throws SignatureException {108if (offset >= precomputedDigest.length) {109offset = RAW_ECDSA_MAX + 1;110return;111}112precomputedDigest[offset++] = b;113}114115// Stores the precomputed message digest value.116@Override117protected void engineUpdate(byte[] b, int off, int len)118throws SignatureException {119if (offset >= precomputedDigest.length) {120offset = RAW_ECDSA_MAX + 1;121return;122}123System.arraycopy(b, off, precomputedDigest, offset, len);124offset += len;125}126127// Stores the precomputed message digest value.128@Override129protected void engineUpdate(ByteBuffer byteBuffer) {130int len = byteBuffer.remaining();131if (len <= 0) {132return;133}134if (offset + len >= precomputedDigest.length) {135offset = RAW_ECDSA_MAX + 1;136return;137}138byteBuffer.get(precomputedDigest, offset, len);139offset += len;140}141142@Override143protected void resetDigest() {144offset = 0;145}146147// Returns the precomputed message digest value.148@Override149protected byte[] getDigestValue() throws SignatureException {150if (offset > RAW_ECDSA_MAX) {151throw new SignatureException("Message digest is too long");152153}154byte[] result = new byte[offset];155System.arraycopy(precomputedDigest, 0, result, 0, offset);156offset = 0;157158return result;159}160}161162// Nested class for SHA1withECDSA signatures163public static final class SHA1 extends ECDSASignature {164public SHA1() {165super("SHA1");166}167}168169// Nested class for SHA224withECDSA signatures170public static final class SHA224 extends ECDSASignature {171public SHA224() {172super("SHA-224");173}174}175176// Nested class for SHA256withECDSA signatures177public static final class SHA256 extends ECDSASignature {178public SHA256() {179super("SHA-256");180}181}182183// Nested class for SHA384withECDSA signatures184public static final class SHA384 extends ECDSASignature {185public SHA384() {186super("SHA-384");187}188}189190// Nested class for SHA512withECDSA signatures191public static final class SHA512 extends ECDSASignature {192public SHA512() {193super("SHA-512");194}195}196197// initialize for verification. See JCA doc198@Override199protected void engineInitVerify(PublicKey publicKey)200throws InvalidKeyException {201ECPublicKey key = (ECPublicKey) ECKeyFactory.toECKey(publicKey);202if (!isCompatible(this.sigParams, key.getParams())) {203throw new InvalidKeyException("Key params does not match signature params");204}205206// Should check that the supplied key is appropriate for signature207// algorithm (e.g. P-256 for SHA256withECDSA)208this.publicKey = key;209this.privateKey = null;210resetDigest();211}212213// initialize for signing. See JCA doc214@Override215protected void engineInitSign(PrivateKey privateKey)216throws InvalidKeyException {217engineInitSign(privateKey, null);218}219220// initialize for signing. See JCA doc221@Override222protected void engineInitSign(PrivateKey privateKey, SecureRandom random)223throws InvalidKeyException {224ECPrivateKey key = (ECPrivateKey) ECKeyFactory.toECKey(privateKey);225if (!isCompatible(this.sigParams, key.getParams())) {226throw new InvalidKeyException("Key params does not match signature params");227}228229// Should check that the supplied key is appropriate for signature230// algorithm (e.g. P-256 for SHA256withECDSA)231this.privateKey = key;232this.publicKey = null;233this.random = random;234resetDigest();235}236237/**238* Resets the message digest if needed.239*/240protected void resetDigest() {241if (needsReset) {242if (messageDigest != null) {243messageDigest.reset();244}245needsReset = false;246}247}248249/**250* Returns the message digest value.251*/252protected byte[] getDigestValue() throws SignatureException {253needsReset = false;254return messageDigest.digest();255}256257// update the signature with the plaintext data. See JCA doc258@Override259protected void engineUpdate(byte b) throws SignatureException {260messageDigest.update(b);261needsReset = true;262}263264// update the signature with the plaintext data. See JCA doc265@Override266protected void engineUpdate(byte[] b, int off, int len)267throws SignatureException {268messageDigest.update(b, off, len);269needsReset = true;270}271272// update the signature with the plaintext data. See JCA doc273@Override274protected void engineUpdate(ByteBuffer byteBuffer) {275int len = byteBuffer.remaining();276if (len <= 0) {277return;278}279280messageDigest.update(byteBuffer);281needsReset = true;282}283284private static boolean isCompatible(ECParameterSpec sigParams,285ECParameterSpec keyParams) {286if (sigParams == null) {287// no restriction on key param288return true;289}290return ECUtil.equals(sigParams, keyParams);291}292293294private byte[] signDigestImpl(ECDSAOperations ops, int seedBits,295byte[] digest, ECPrivateKeyImpl privImpl, SecureRandom random)296throws SignatureException {297298byte[] seedBytes = new byte[(seedBits + 7) / 8];299byte[] s = privImpl.getArrayS();300301// Attempt to create the signature in a loop that uses new random input302// each time. The chance of failure is very small assuming the303// implementation derives the nonce using extra bits304int numAttempts = 128;305for (int i = 0; i < numAttempts; i++) {306random.nextBytes(seedBytes);307ECDSAOperations.Seed seed = new ECDSAOperations.Seed(seedBytes);308try {309return ops.signDigest(s, digest, seed);310} catch (IntermediateValueException ex) {311// try again in the next iteration312}313}314315throw new SignatureException("Unable to produce signature after "316+ numAttempts + " attempts");317}318319320private Optional<byte[]> signDigestImpl(ECPrivateKey privateKey,321byte[] digest, SecureRandom random) throws SignatureException {322323if (! (privateKey instanceof ECPrivateKeyImpl)) {324return Optional.empty();325}326ECPrivateKeyImpl privImpl = (ECPrivateKeyImpl) privateKey;327ECParameterSpec params = privateKey.getParams();328329// seed is the key size + 64 bits330int seedBits = params.getOrder().bitLength() + 64;331Optional<ECDSAOperations> opsOpt =332ECDSAOperations.forParameters(params);333if (!opsOpt.isPresent()) {334return Optional.empty();335} else {336byte[] sig = signDigestImpl(opsOpt.get(), seedBits, digest,337privImpl, random);338return Optional.of(sig);339}340}341342private byte[] signDigestNative(ECPrivateKey privateKey, byte[] digest,343SecureRandom random) throws SignatureException {344345byte[] s = privateKey.getS().toByteArray();346ECParameterSpec params = privateKey.getParams();347348// DER OID349byte[] encodedParams = ECUtil.encodeECParameterSpec(null, params);350int orderLength = params.getOrder().bitLength();351352// seed is twice the order length (in bytes) plus 1353byte[] seed = new byte[(((orderLength + 7) >> 3) + 1) * 2];354355random.nextBytes(seed);356357// random bits needed for timing countermeasures358int timingArgument = random.nextInt();359// values must be non-zero to enable countermeasures360timingArgument |= 1;361362try {363return signDigest(digest, s, encodedParams, seed,364timingArgument);365} catch (GeneralSecurityException e) {366throw new SignatureException("Could not sign data", e);367}368}369370// sign the data and return the signature. See JCA doc371@Override372protected byte[] engineSign() throws SignatureException {373374if (random == null) {375random = JCAUtil.getSecureRandom();376}377378byte[] digest = getDigestValue();379Optional<byte[]> sigOpt = signDigestImpl(privateKey, digest, random);380byte[] sig;381if (sigOpt.isPresent()) {382sig = sigOpt.get();383} else {384sig = signDigestNative(privateKey, digest, random);385}386387return ECUtil.encodeSignature(sig);388}389390// verify the data and return the result. See JCA doc391@Override392protected boolean engineVerify(byte[] signature) throws SignatureException {393394byte[] w;395ECParameterSpec params = publicKey.getParams();396// DER OID397byte[] encodedParams = ECUtil.encodeECParameterSpec(null, params);398399if (publicKey instanceof ECPublicKeyImpl) {400w = ((ECPublicKeyImpl) publicKey).getEncodedPublicValue();401} else { // instanceof ECPublicKey402w = ECUtil.encodePoint(publicKey.getW(), params.getCurve());403}404405try {406407return verifySignedDigest(408ECUtil.decodeSignature(signature), getDigestValue(),409w, encodedParams);410411} catch (GeneralSecurityException e) {412throw new SignatureException("Could not verify signature", e);413}414}415416// set parameter, not supported. See JCA doc417@Override418@Deprecated419protected void engineSetParameter(String param, Object value)420throws InvalidParameterException {421throw new UnsupportedOperationException("setParameter() not supported");422}423424@Override425protected void engineSetParameter(AlgorithmParameterSpec params)426throws InvalidAlgorithmParameterException {427if (params != null && !(params instanceof ECParameterSpec)) {428throw new InvalidAlgorithmParameterException("No parameter accepted");429}430ECKey key = (this.privateKey == null? this.publicKey : this.privateKey);431if ((key != null) && !isCompatible((ECParameterSpec)params, key.getParams())) {432throw new InvalidAlgorithmParameterException433("Signature params does not match key params");434}435436sigParams = (ECParameterSpec) params;437}438439// get parameter, not supported. See JCA doc440@Override441@Deprecated442protected Object engineGetParameter(String param)443throws InvalidParameterException {444throw new UnsupportedOperationException("getParameter() not supported");445}446447@Override448protected AlgorithmParameters engineGetParameters() {449if (sigParams == null) {450return null;451}452try {453AlgorithmParameters ap = AlgorithmParameters.getInstance("EC");454ap.init(sigParams);455return ap;456} catch (Exception e) {457// should never happen458throw new ProviderException("Error retrieving EC parameters", e);459}460}461462/**463* Signs the digest using the private key.464*465* @param digest the digest to be signed.466* @param s the private key's S value.467* @param encodedParams the curve's DER encoded object identifier.468* @param seed the random seed.469* @param timing When non-zero, the implmentation will use timing470* countermeasures to hide secrets from timing channels. The EC471* implementation will disable the countermeasures when this value is472* zero, because the underlying EC functions are shared by several473* crypto operations, some of which do not use the countermeasures.474* The high-order 31 bits must be uniformly random. The entropy from475* these bits is used by the countermeasures.476*477* @return byte[] the signature.478*/479private static native byte[] signDigest(byte[] digest, byte[] s,480byte[] encodedParams, byte[] seed, int timing)481throws GeneralSecurityException;482483/**484* Verifies the signed digest using the public key.485*486* @param signature the signature to be verified. It is encoded487* as a concatenation of the key's R and S values.488* @param digest the digest to be used.489* @param w the public key's W point (in uncompressed form).490* @param encodedParams the curve's DER encoded object identifier.491*492* @return boolean true if the signature is successfully verified.493*/494private static native boolean verifySignedDigest(byte[] signature,495byte[] digest, byte[] w, byte[] encodedParams)496throws GeneralSecurityException;497}498499500