Path: blob/master/src/java.base/share/classes/sun/security/ssl/CertificateVerify.java
41159 views
/*1* Copyright (c) 2015, 2021, 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.ssl;2627import java.io.IOException;28import java.nio.ByteBuffer;29import java.security.*;30import java.text.MessageFormat;31import java.util.Arrays;32import java.util.Locale;33import java.util.Map;34import sun.security.ssl.SSLHandshake.HandshakeMessage;35import sun.security.ssl.X509Authentication.X509Credentials;36import sun.security.ssl.X509Authentication.X509Possession;37import sun.security.util.HexDumpEncoder;3839/**40* Pack of the CertificateVerify handshake message.41*/42final class CertificateVerify {43static final SSLConsumer s30HandshakeConsumer =44new S30CertificateVerifyConsumer();45static final HandshakeProducer s30HandshakeProducer =46new S30CertificateVerifyProducer();4748static final SSLConsumer t10HandshakeConsumer =49new T10CertificateVerifyConsumer();50static final HandshakeProducer t10HandshakeProducer =51new T10CertificateVerifyProducer();5253static final SSLConsumer t12HandshakeConsumer =54new T12CertificateVerifyConsumer();55static final HandshakeProducer t12HandshakeProducer =56new T12CertificateVerifyProducer();5758static final SSLConsumer t13HandshakeConsumer =59new T13CertificateVerifyConsumer();60static final HandshakeProducer t13HandshakeProducer =61new T13CertificateVerifyProducer();6263/**64* The CertificateVerify handshake message (SSL 3.0).65*/66static final class S30CertificateVerifyMessage extends HandshakeMessage {67// signature bytes68private final byte[] signature;6970S30CertificateVerifyMessage(HandshakeContext context,71X509Possession x509Possession) throws IOException {72super(context);7374// This happens in client side only.75ClientHandshakeContext chc = (ClientHandshakeContext)context;76byte[] temporary;77String algorithm = x509Possession.popPrivateKey.getAlgorithm();78try {79Signature signer =80getSignature(algorithm, x509Possession.popPrivateKey);81byte[] hashes = chc.handshakeHash.digest(algorithm,82chc.handshakeSession.getMasterSecret());83signer.update(hashes);84temporary = signer.sign();85} catch (NoSuchAlgorithmException nsae) {86throw chc.conContext.fatal(Alert.INTERNAL_ERROR,87"Unsupported signature algorithm (" + algorithm +88") used in CertificateVerify handshake message", nsae);89} catch (GeneralSecurityException gse) {90throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,91"Cannot produce CertificateVerify signature", gse);92}9394this.signature = temporary;95}9697S30CertificateVerifyMessage(HandshakeContext context,98ByteBuffer m) throws IOException {99super(context);100101// This happens in server side only.102ServerHandshakeContext shc = (ServerHandshakeContext)context;103104// digitally-signed struct {105// select(SignatureAlgorithm) {106// case anonymous: struct { };107// case rsa:108// opaque md5_hash[16];109// opaque sha_hash[20];110// case dsa:111// opaque sha_hash[20];112// };113// } Signature;114if (m.remaining() < 2) {115throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,116"Invalid CertificateVerify message: no sufficient data");117}118119// read and verify the signature120this.signature = Record.getBytes16(m);121X509Credentials x509Credentials = null;122for (SSLCredentials cd : shc.handshakeCredentials) {123if (cd instanceof X509Credentials) {124x509Credentials = (X509Credentials)cd;125break;126}127}128129if (x509Credentials == null ||130x509Credentials.popPublicKey == null) {131throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,132"No X509 credentials negotiated for CertificateVerify");133}134135String algorithm = x509Credentials.popPublicKey.getAlgorithm();136try {137Signature signer =138getSignature(algorithm, x509Credentials.popPublicKey);139byte[] hashes = shc.handshakeHash.digest(algorithm,140shc.handshakeSession.getMasterSecret());141signer.update(hashes);142if (!signer.verify(signature)) {143throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,144"Invalid CertificateVerify message: invalid signature");145}146} catch (NoSuchAlgorithmException nsae) {147throw shc.conContext.fatal(Alert.INTERNAL_ERROR,148"Unsupported signature algorithm (" + algorithm +149") used in CertificateVerify handshake message", nsae);150} catch (GeneralSecurityException gse) {151throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,152"Cannot verify CertificateVerify signature", gse);153}154}155156@Override157public SSLHandshake handshakeType() {158return SSLHandshake.CERTIFICATE_VERIFY;159}160161@Override162public int messageLength() {163return 2 + signature.length; // 2: length of signature164}165166@Override167public void send(HandshakeOutStream hos) throws IOException {168hos.putBytes16(signature);169}170171@Override172public String toString() {173MessageFormat messageFormat = new MessageFormat(174"\"CertificateVerify\": '{'\n" +175" \"signature\": '{'\n" +176"{0}\n" +177" '}'\n" +178"'}'",179Locale.ENGLISH);180181HexDumpEncoder hexEncoder = new HexDumpEncoder();182Object[] messageFields = {183Utilities.indent(184hexEncoder.encodeBuffer(signature), " ")185};186187return messageFormat.format(messageFields);188}189190/*191* Get the Signature object appropriate for verification using the192* given signature algorithm.193*/194private static Signature getSignature(String algorithm,195Key key) throws GeneralSecurityException {196Signature signer;197switch (algorithm) {198case "RSA":199signer = Signature.getInstance(JsseJce.SIGNATURE_RAWRSA);200break;201case "DSA":202signer = Signature.getInstance(JsseJce.SIGNATURE_RAWDSA);203break;204case "EC":205signer = Signature.getInstance(JsseJce.SIGNATURE_RAWECDSA);206break;207default:208throw new SignatureException("Unrecognized algorithm: "209+ algorithm);210}211212if (signer != null) {213if (key instanceof PublicKey) {214signer.initVerify((PublicKey)(key));215} else {216signer.initSign((PrivateKey)key);217}218}219220return signer;221}222}223224/**225* The "CertificateVerify" handshake message producer.226*/227private static final228class S30CertificateVerifyProducer implements HandshakeProducer {229// Prevent instantiation of this class.230private S30CertificateVerifyProducer() {231// blank232}233234@Override235public byte[] produce(ConnectionContext context,236HandshakeMessage message) throws IOException {237// The producing happens in client side only.238ClientHandshakeContext chc = (ClientHandshakeContext)context;239240X509Possession x509Possession = null;241for (SSLPossession possession : chc.handshakePossessions) {242if (possession instanceof X509Possession) {243x509Possession = (X509Possession)possession;244break;245}246}247248if (x509Possession == null ||249x509Possession.popPrivateKey == null) {250if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {251SSLLogger.fine(252"No X.509 credentials negotiated for CertificateVerify");253}254255return null;256}257258S30CertificateVerifyMessage cvm =259new S30CertificateVerifyMessage(chc, x509Possession);260if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {261SSLLogger.fine(262"Produced CertificateVerify handshake message", cvm);263}264265// Output the handshake message.266cvm.write(chc.handshakeOutput);267chc.handshakeOutput.flush();268269// The handshake message has been delivered.270return null;271}272}273274/**275* The "CertificateVerify" handshake message consumer.276*/277private static final278class S30CertificateVerifyConsumer implements SSLConsumer {279// Prevent instantiation of this class.280private S30CertificateVerifyConsumer() {281// blank282}283284@Override285public void consume(ConnectionContext context,286ByteBuffer message) throws IOException {287// The consuming happens in server side only.288ServerHandshakeContext shc = (ServerHandshakeContext)context;289290// Clean up this consumer291shc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_VERIFY.id);292293// Ensure that the CV message follows the CKE294if (shc.handshakeConsumers.containsKey(295SSLHandshake.CLIENT_KEY_EXCHANGE.id)) {296throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,297"Unexpected CertificateVerify handshake message");298}299300S30CertificateVerifyMessage cvm =301new S30CertificateVerifyMessage(shc, message);302if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {303SSLLogger.fine(304"Consuming CertificateVerify handshake message", cvm);305}306307//308// update309//310// Need no additional validation.311312//313// produce314//315// Need no new handshake message producers here.316}317}318319/**320* The CertificateVerify handshake message (TLS 1.0/1.1).321*/322static final class T10CertificateVerifyMessage extends HandshakeMessage {323// signature bytes324private final byte[] signature;325326T10CertificateVerifyMessage(HandshakeContext context,327X509Possession x509Possession) throws IOException {328super(context);329330// This happens in client side only.331ClientHandshakeContext chc = (ClientHandshakeContext)context;332byte[] temporary;333String algorithm = x509Possession.popPrivateKey.getAlgorithm();334try {335Signature signer =336getSignature(algorithm, x509Possession.popPrivateKey);337byte[] hashes = chc.handshakeHash.digest(algorithm);338signer.update(hashes);339temporary = signer.sign();340} catch (NoSuchAlgorithmException nsae) {341throw chc.conContext.fatal(Alert.INTERNAL_ERROR,342"Unsupported signature algorithm (" + algorithm +343") used in CertificateVerify handshake message", nsae);344} catch (GeneralSecurityException gse) {345throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,346"Cannot produce CertificateVerify signature", gse);347}348349this.signature = temporary;350}351352T10CertificateVerifyMessage(HandshakeContext context,353ByteBuffer m) throws IOException {354super(context);355356// This happens in server side only.357ServerHandshakeContext shc = (ServerHandshakeContext)context;358359// digitally-signed struct {360// select(SignatureAlgorithm) {361// case anonymous: struct { };362// case rsa:363// opaque md5_hash[16];364// opaque sha_hash[20];365// case dsa:366// opaque sha_hash[20];367// };368// } Signature;369if (m.remaining() < 2) {370throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,371"Invalid CertificateVerify message: no sufficient data");372}373374// read and verify the signature375this.signature = Record.getBytes16(m);376X509Credentials x509Credentials = null;377for (SSLCredentials cd : shc.handshakeCredentials) {378if (cd instanceof X509Credentials) {379x509Credentials = (X509Credentials)cd;380break;381}382}383384if (x509Credentials == null ||385x509Credentials.popPublicKey == null) {386throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,387"No X509 credentials negotiated for CertificateVerify");388}389390String algorithm = x509Credentials.popPublicKey.getAlgorithm();391try {392Signature signer =393getSignature(algorithm, x509Credentials.popPublicKey);394byte[] hashes = shc.handshakeHash.digest(algorithm);395signer.update(hashes);396if (!signer.verify(signature)) {397throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,398"Invalid CertificateVerify message: invalid signature");399}400} catch (NoSuchAlgorithmException nsae) {401throw shc.conContext.fatal(Alert.INTERNAL_ERROR,402"Unsupported signature algorithm (" + algorithm +403") used in CertificateVerify handshake message", nsae);404} catch (GeneralSecurityException gse) {405throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,406"Cannot verify CertificateVerify signature", gse);407}408}409410@Override411public SSLHandshake handshakeType() {412return SSLHandshake.CERTIFICATE_VERIFY;413}414415@Override416public int messageLength() {417return 2 + signature.length; // 2: length of signature418}419420@Override421public void send(HandshakeOutStream hos) throws IOException {422hos.putBytes16(signature);423}424425@Override426public String toString() {427MessageFormat messageFormat = new MessageFormat(428"\"CertificateVerify\": '{'\n" +429" \"signature\": '{'\n" +430"{0}\n" +431" '}'\n" +432"'}'",433Locale.ENGLISH);434435HexDumpEncoder hexEncoder = new HexDumpEncoder();436Object[] messageFields = {437Utilities.indent(438hexEncoder.encodeBuffer(signature), " ")439};440441return messageFormat.format(messageFields);442}443444/*445* Get the Signature object appropriate for verification using the446* given signature algorithm.447*/448private static Signature getSignature(String algorithm,449Key key) throws GeneralSecurityException {450Signature signer;451switch (algorithm) {452case "RSA":453signer = Signature.getInstance(JsseJce.SIGNATURE_RAWRSA);454break;455case "DSA":456signer = Signature.getInstance(JsseJce.SIGNATURE_RAWDSA);457break;458case "EC":459signer = Signature.getInstance(JsseJce.SIGNATURE_RAWECDSA);460break;461case "EdDSA":462signer = Signature.getInstance(JsseJce.SIGNATURE_EDDSA);463break;464default:465throw new SignatureException("Unrecognized algorithm: "466+ algorithm);467}468469if (signer != null) {470if (key instanceof PublicKey) {471signer.initVerify((PublicKey)(key));472} else {473signer.initSign((PrivateKey)key);474}475}476477return signer;478}479}480481/**482* The "CertificateVerify" handshake message producer.483*/484private static final485class T10CertificateVerifyProducer implements HandshakeProducer {486// Prevent instantiation of this class.487private T10CertificateVerifyProducer() {488// blank489}490491@Override492public byte[] produce(ConnectionContext context,493HandshakeMessage message) throws IOException {494// The producing happens in client side only.495ClientHandshakeContext chc = (ClientHandshakeContext)context;496X509Possession x509Possession = null;497for (SSLPossession possession : chc.handshakePossessions) {498if (possession instanceof X509Possession) {499x509Possession = (X509Possession)possession;500break;501}502}503504if (x509Possession == null ||505x509Possession.popPrivateKey == null) {506if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {507SSLLogger.fine(508"No X.509 credentials negotiated for CertificateVerify");509}510511return null;512}513514T10CertificateVerifyMessage cvm =515new T10CertificateVerifyMessage(chc, x509Possession);516if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {517SSLLogger.fine(518"Produced CertificateVerify handshake message", cvm);519}520521// Output the handshake message.522cvm.write(chc.handshakeOutput);523chc.handshakeOutput.flush();524525// The handshake message has been delivered.526return null;527}528}529530/**531* The "CertificateVerify" handshake message consumer.532*/533private static final534class T10CertificateVerifyConsumer implements SSLConsumer {535// Prevent instantiation of this class.536private T10CertificateVerifyConsumer() {537// blank538}539540@Override541public void consume(ConnectionContext context,542ByteBuffer message) throws IOException {543// The consuming happens in server side only.544ServerHandshakeContext shc = (ServerHandshakeContext)context;545546// Clean up this consumer547shc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_VERIFY.id);548549// Ensure that the CV message follows the CKE550if (shc.handshakeConsumers.containsKey(551SSLHandshake.CLIENT_KEY_EXCHANGE.id)) {552throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,553"Unexpected CertificateVerify handshake message");554}555556T10CertificateVerifyMessage cvm =557new T10CertificateVerifyMessage(shc, message);558if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {559SSLLogger.fine(560"Consuming CertificateVerify handshake message", cvm);561}562563//564// update565//566// Need no additional validation.567568//569// produce570//571// Need no new handshake message producers here. }572}573}574575/**576* The CertificateVerify handshake message (TLS 1.2).577*/578static final class T12CertificateVerifyMessage extends HandshakeMessage {579// the signature algorithm580private final SignatureScheme signatureScheme;581582// signature bytes583private final byte[] signature;584585T12CertificateVerifyMessage(HandshakeContext context,586X509Possession x509Possession) throws IOException {587super(context);588589// This happens in client side only.590ClientHandshakeContext chc = (ClientHandshakeContext)context;591Map.Entry<SignatureScheme, Signature> schemeAndSigner =592SignatureScheme.getSignerOfPreferableAlgorithm(593chc.algorithmConstraints,594chc.peerRequestedSignatureSchemes,595x509Possession,596chc.negotiatedProtocol);597if (schemeAndSigner == null) {598// Unlikely, the credentials generator should have599// selected the preferable signature algorithm properly.600throw chc.conContext.fatal(Alert.INTERNAL_ERROR,601"No supported CertificateVerify signature algorithm for " +602x509Possession.popPrivateKey.getAlgorithm() +603" key");604}605606this.signatureScheme = schemeAndSigner.getKey();607byte[] temporary;608try {609Signature signer = schemeAndSigner.getValue();610signer.update(chc.handshakeHash.archived());611temporary = signer.sign();612} catch (SignatureException ikse) {613throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,614"Cannot produce CertificateVerify signature", ikse);615}616617this.signature = temporary;618}619620T12CertificateVerifyMessage(HandshakeContext handshakeContext,621ByteBuffer m) throws IOException {622super(handshakeContext);623624// This happens in server side only.625ServerHandshakeContext shc =626(ServerHandshakeContext)handshakeContext;627628// struct {629// SignatureAndHashAlgorithm algorithm;630// opaque signature<0..2^16-1>;631// } DigitallySigned;632if (m.remaining() < 4) {633throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,634"Invalid CertificateVerify message: no sufficient data");635}636637// SignatureAndHashAlgorithm algorithm638int ssid = Record.getInt16(m);639this.signatureScheme = SignatureScheme.valueOf(ssid);640if (signatureScheme == null) {641throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,642"Invalid signature algorithm (" + ssid +643") used in CertificateVerify handshake message");644}645646if (!shc.localSupportedSignAlgs.contains(signatureScheme)) {647throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,648"Unsupported signature algorithm (" +649signatureScheme.name +650") used in CertificateVerify handshake message");651}652653// read and verify the signature654X509Credentials x509Credentials = null;655for (SSLCredentials cd : shc.handshakeCredentials) {656if (cd instanceof X509Credentials) {657x509Credentials = (X509Credentials)cd;658break;659}660}661662if (x509Credentials == null ||663x509Credentials.popPublicKey == null) {664throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,665"No X509 credentials negotiated for CertificateVerify");666}667668// opaque signature<0..2^16-1>;669this.signature = Record.getBytes16(m);670try {671Signature signer =672signatureScheme.getVerifier(x509Credentials.popPublicKey);673signer.update(shc.handshakeHash.archived());674if (!signer.verify(signature)) {675throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,676"Invalid CertificateVerify signature");677}678} catch (NoSuchAlgorithmException |679InvalidAlgorithmParameterException nsae) {680throw shc.conContext.fatal(Alert.INTERNAL_ERROR,681"Unsupported signature algorithm (" +682signatureScheme.name +683") used in CertificateVerify handshake message", nsae);684} catch (InvalidKeyException | SignatureException ikse) {685throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,686"Cannot verify CertificateVerify signature", ikse);687}688}689690@Override691public SSLHandshake handshakeType() {692return SSLHandshake.CERTIFICATE_VERIFY;693}694695@Override696public int messageLength() {697return 4 + signature.length; // 2: signature algorithm698// +2: length of signature699}700701@Override702public void send(HandshakeOutStream hos) throws IOException {703hos.putInt16(signatureScheme.id);704hos.putBytes16(signature);705}706707@Override708public String toString() {709MessageFormat messageFormat = new MessageFormat(710"\"CertificateVerify\": '{'\n" +711" \"signature algorithm\": {0}\n" +712" \"signature\": '{'\n" +713"{1}\n" +714" '}'\n" +715"'}'",716Locale.ENGLISH);717718HexDumpEncoder hexEncoder = new HexDumpEncoder();719Object[] messageFields = {720signatureScheme.name,721Utilities.indent(722hexEncoder.encodeBuffer(signature), " ")723};724725return messageFormat.format(messageFields);726}727}728729/**730* The "CertificateVerify" handshake message producer.731*/732private static final733class T12CertificateVerifyProducer implements HandshakeProducer {734// Prevent instantiation of this class.735private T12CertificateVerifyProducer() {736// blank737}738739@Override740public byte[] produce(ConnectionContext context,741HandshakeMessage message) throws IOException {742// The producing happens in client side only.743ClientHandshakeContext chc = (ClientHandshakeContext)context;744745X509Possession x509Possession = null;746for (SSLPossession possession : chc.handshakePossessions) {747if (possession instanceof X509Possession) {748x509Possession = (X509Possession)possession;749break;750}751}752753if (x509Possession == null ||754x509Possession.popPrivateKey == null) {755if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {756SSLLogger.fine(757"No X.509 credentials negotiated for CertificateVerify");758}759760return null;761}762763T12CertificateVerifyMessage cvm =764new T12CertificateVerifyMessage(chc, x509Possession);765if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {766SSLLogger.fine(767"Produced CertificateVerify handshake message", cvm);768}769770// Output the handshake message.771cvm.write(chc.handshakeOutput);772chc.handshakeOutput.flush();773774// The handshake message has been delivered.775return null;776}777}778779/**780* The "CertificateVerify" handshake message consumer.781*/782private static final783class T12CertificateVerifyConsumer implements SSLConsumer {784// Prevent instantiation of this class.785private T12CertificateVerifyConsumer() {786// blank787}788789@Override790public void consume(ConnectionContext context,791ByteBuffer message) throws IOException {792// The consuming happens in server side only.793ServerHandshakeContext shc = (ServerHandshakeContext)context;794795// Clean up this consumer796shc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_VERIFY.id);797798// Ensure that the CV message follows the CKE799if (shc.handshakeConsumers.containsKey(800SSLHandshake.CLIENT_KEY_EXCHANGE.id)) {801throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,802"Unexpected CertificateVerify handshake message");803}804805T12CertificateVerifyMessage cvm =806new T12CertificateVerifyMessage(shc, message);807if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {808SSLLogger.fine(809"Consuming CertificateVerify handshake message", cvm);810}811812//813// update814//815// Need no additional validation.816817//818// produce819//820// Need no new handshake message producers here.821}822}823824/**825* The CertificateVerify handshake message (TLS 1.3).826*/827static final class T13CertificateVerifyMessage extends HandshakeMessage {828private static final byte[] serverSignHead = new byte[] {829// repeated 0x20 for 64 times830(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,831(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,832(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,833(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,834(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,835(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,836(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,837(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,838(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,839(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,840(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,841(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,842(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,843(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,844(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,845(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,846847// "TLS 1.3, server CertificateVerify" + 0x00848(byte)0x54, (byte)0x4c, (byte)0x53, (byte)0x20,849(byte)0x31, (byte)0x2e, (byte)0x33, (byte)0x2c,850(byte)0x20, (byte)0x73, (byte)0x65, (byte)0x72,851(byte)0x76, (byte)0x65, (byte)0x72, (byte)0x20,852(byte)0x43, (byte)0x65, (byte)0x72, (byte)0x74,853(byte)0x69, (byte)0x66, (byte)0x69, (byte)0x63,854(byte)0x61, (byte)0x74, (byte)0x65, (byte)0x56,855(byte)0x65, (byte)0x72, (byte)0x69, (byte)0x66,856(byte)0x79, (byte)0x00857};858859private static final byte[] clientSignHead = new byte[] {860// repeated 0x20 for 64 times861(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,862(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,863(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,864(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,865(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,866(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,867(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,868(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,869(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,870(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,871(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,872(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,873(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,874(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,875(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,876(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,877878// "TLS 1.3, client CertificateVerify" + 0x00879(byte)0x54, (byte)0x4c, (byte)0x53, (byte)0x20,880(byte)0x31, (byte)0x2e, (byte)0x33, (byte)0x2c,881(byte)0x20, (byte)0x63, (byte)0x6c, (byte)0x69,882(byte)0x65, (byte)0x6e, (byte)0x74, (byte)0x20,883(byte)0x43, (byte)0x65, (byte)0x72, (byte)0x74,884(byte)0x69, (byte)0x66, (byte)0x69, (byte)0x63,885(byte)0x61, (byte)0x74, (byte)0x65, (byte)0x56,886(byte)0x65, (byte)0x72, (byte)0x69, (byte)0x66,887(byte)0x79, (byte)0x00888};889890891// the signature algorithm892private final SignatureScheme signatureScheme;893894// signature bytes895private final byte[] signature;896897T13CertificateVerifyMessage(HandshakeContext context,898X509Possession x509Possession) throws IOException {899super(context);900901Map.Entry<SignatureScheme, Signature> schemeAndSigner =902SignatureScheme.getSignerOfPreferableAlgorithm(903context.algorithmConstraints,904context.peerRequestedSignatureSchemes,905x509Possession,906context.negotiatedProtocol);907if (schemeAndSigner == null) {908// Unlikely, the credentials generator should have909// selected the preferable signature algorithm properly.910throw context.conContext.fatal(Alert.INTERNAL_ERROR,911"No supported CertificateVerify signature algorithm for " +912x509Possession.popPrivateKey.getAlgorithm() +913" key");914}915916this.signatureScheme = schemeAndSigner.getKey();917918byte[] hashValue = context.handshakeHash.digest();919byte[] contentCovered;920if (context.sslConfig.isClientMode) {921contentCovered = Arrays.copyOf(clientSignHead,922clientSignHead.length + hashValue.length);923System.arraycopy(hashValue, 0, contentCovered,924clientSignHead.length, hashValue.length);925} else {926contentCovered = Arrays.copyOf(serverSignHead,927serverSignHead.length + hashValue.length);928System.arraycopy(hashValue, 0, contentCovered,929serverSignHead.length, hashValue.length);930}931932byte[] temporary;933try {934Signature signer = schemeAndSigner.getValue();935signer.update(contentCovered);936temporary = signer.sign();937} catch (SignatureException ikse) {938throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,939"Cannot produce CertificateVerify signature", ikse);940}941942this.signature = temporary;943}944945T13CertificateVerifyMessage(HandshakeContext context,946ByteBuffer m) throws IOException {947super(context);948949// struct {950// SignatureAndHashAlgorithm algorithm;951// opaque signature<0..2^16-1>;952// } DigitallySigned;953if (m.remaining() < 4) {954throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER,955"Invalid CertificateVerify message: no sufficient data");956}957958// SignatureAndHashAlgorithm algorithm959int ssid = Record.getInt16(m);960this.signatureScheme = SignatureScheme.valueOf(ssid);961if (signatureScheme == null) {962throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,963"Invalid signature algorithm (" + ssid +964") used in CertificateVerify handshake message");965}966967if (!context.localSupportedSignAlgs.contains(signatureScheme)) {968throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,969"Unsupported signature algorithm (" +970signatureScheme.name +971") used in CertificateVerify handshake message");972}973974// read and verify the signature975X509Credentials x509Credentials = null;976for (SSLCredentials cd : context.handshakeCredentials) {977if (cd instanceof X509Credentials) {978x509Credentials = (X509Credentials)cd;979break;980}981}982983if (x509Credentials == null ||984x509Credentials.popPublicKey == null) {985throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,986"No X509 credentials negotiated for CertificateVerify");987}988989// opaque signature<0..2^16-1>;990this.signature = Record.getBytes16(m);991992byte[] hashValue = context.handshakeHash.digest();993byte[] contentCovered;994if (context.sslConfig.isClientMode) {995contentCovered = Arrays.copyOf(serverSignHead,996serverSignHead.length + hashValue.length);997System.arraycopy(hashValue, 0, contentCovered,998serverSignHead.length, hashValue.length);999} else {1000contentCovered = Arrays.copyOf(clientSignHead,1001clientSignHead.length + hashValue.length);1002System.arraycopy(hashValue, 0, contentCovered,1003clientSignHead.length, hashValue.length);1004}10051006try {1007Signature signer =1008signatureScheme.getVerifier(x509Credentials.popPublicKey);1009signer.update(contentCovered);1010if (!signer.verify(signature)) {1011throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,1012"Invalid CertificateVerify signature");1013}1014} catch (NoSuchAlgorithmException |1015InvalidAlgorithmParameterException nsae) {1016throw context.conContext.fatal(Alert.INTERNAL_ERROR,1017"Unsupported signature algorithm (" +1018signatureScheme.name +1019") used in CertificateVerify handshake message", nsae);1020} catch (InvalidKeyException | SignatureException ikse) {1021throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,1022"Cannot verify CertificateVerify signature", ikse);1023}1024}10251026@Override1027public SSLHandshake handshakeType() {1028return SSLHandshake.CERTIFICATE_VERIFY;1029}10301031@Override1032public int messageLength() {1033return 4 + signature.length; // 2: signature algorithm1034// +2: length of signature1035}10361037@Override1038public void send(HandshakeOutStream hos) throws IOException {1039hos.putInt16(signatureScheme.id);1040hos.putBytes16(signature);1041}10421043@Override1044public String toString() {1045MessageFormat messageFormat = new MessageFormat(1046"\"CertificateVerify\": '{'\n" +1047" \"signature algorithm\": {0}\n" +1048" \"signature\": '{'\n" +1049"{1}\n" +1050" '}'\n" +1051"'}'",1052Locale.ENGLISH);10531054HexDumpEncoder hexEncoder = new HexDumpEncoder();1055Object[] messageFields = {1056signatureScheme.name,1057Utilities.indent(1058hexEncoder.encodeBuffer(signature), " ")1059};10601061return messageFormat.format(messageFields);1062}1063}10641065/**1066* The "CertificateVerify" handshake message producer.1067*/1068private static final1069class T13CertificateVerifyProducer implements HandshakeProducer {1070// Prevent instantiation of this class.1071private T13CertificateVerifyProducer() {1072// blank1073}10741075@Override1076public byte[] produce(ConnectionContext context,1077HandshakeMessage message) throws IOException {1078// The producing happens in handshake context only.1079HandshakeContext hc = (HandshakeContext)context;10801081X509Possession x509Possession = null;1082for (SSLPossession possession : hc.handshakePossessions) {1083if (possession instanceof X509Possession) {1084x509Possession = (X509Possession)possession;1085break;1086}1087}10881089if (x509Possession == null ||1090x509Possession.popPrivateKey == null) {1091if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {1092SSLLogger.fine(1093"No X.509 credentials negotiated for CertificateVerify");1094}10951096return null;1097}10981099if (hc.sslConfig.isClientMode) {1100return onProduceCertificateVerify(1101(ClientHandshakeContext)context, x509Possession);1102} else {1103return onProduceCertificateVerify(1104(ServerHandshakeContext)context, x509Possession);1105}1106}11071108private byte[] onProduceCertificateVerify(ServerHandshakeContext shc,1109X509Possession x509Possession) throws IOException {1110T13CertificateVerifyMessage cvm =1111new T13CertificateVerifyMessage(shc, x509Possession);1112if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {1113SSLLogger.fine(1114"Produced server CertificateVerify handshake message", cvm);1115}11161117// Output the handshake message.1118cvm.write(shc.handshakeOutput);1119shc.handshakeOutput.flush();11201121// The handshake message has been delivered.1122return null;1123}11241125private byte[] onProduceCertificateVerify(ClientHandshakeContext chc,1126X509Possession x509Possession) throws IOException {1127T13CertificateVerifyMessage cvm =1128new T13CertificateVerifyMessage(chc, x509Possession);1129if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {1130SSLLogger.fine(1131"Produced client CertificateVerify handshake message", cvm);1132}11331134// Output the handshake message.1135cvm.write(chc.handshakeOutput);1136chc.handshakeOutput.flush();11371138// The handshake message has been delivered.1139return null;1140}1141}11421143/**1144* The "CertificateVerify" handshake message consumer.1145*/1146private static final1147class T13CertificateVerifyConsumer implements SSLConsumer {1148// Prevent instantiation of this class.1149private T13CertificateVerifyConsumer() {1150// blank1151}11521153@Override1154public void consume(ConnectionContext context,1155ByteBuffer message) throws IOException {1156// The producing happens in handshake context only.1157HandshakeContext hc = (HandshakeContext)context;11581159// Clean up this consumer1160hc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_VERIFY.id);11611162T13CertificateVerifyMessage cvm =1163new T13CertificateVerifyMessage(hc, message);1164if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {1165SSLLogger.fine(1166"Consuming CertificateVerify handshake message", cvm);1167}11681169//1170// update1171//1172// Need no additional validation.11731174//1175// produce1176//1177// Need no new handshake message producers here.1178}1179}1180}118111821183