コード例 #1
0
  /**
   * The ServerKeyExchange message is sent by the server only when the server {@link
   * CertificateMessage} (if sent) does not contain enough data to allow the client to exchange a
   * premaster secret. Used when the key exchange is ECDH. The client tries to verify the server's
   * signature and on success prepares the ECDH key agreement.
   *
   * @param message the server's {@link ServerKeyExchange} message.
   * @throws HandshakeException if the message can't be verified.
   */
  private void receivedServerKeyExchange(ECDHServerKeyExchange message) throws HandshakeException {
    if (serverKeyExchange != null
        && (serverKeyExchange.getMessageSeq() == message.getMessageSeq())) {
      // discard duplicate message
      return;
    }

    serverKeyExchange = message;
    message.verifySignature(serverPublicKey, clientRandom, serverRandom);

    // get the curve parameter spec by the named curve id
    ECParameterSpec params = ECDHServerKeyExchange.NAMED_CURVE_PARAMETERS.get(message.getCurveId());
    if (params == null) {
      AlertMessage alert = new AlertMessage(AlertLevel.FATAL, AlertDescription.HANDSHAKE_FAILURE);
      throw new HandshakeException("Server used unsupported elliptic curve for ECDH", alert);
    }

    ephemeralServerPublicKey = message.getPublicKey(params);
    ecdhe = new ECDHECryptography(ephemeralServerPublicKey.getParams());
  }
コード例 #2
0
  /**
   * The ServerHelloDone message is sent by the server to indicate the end of the ServerHello and
   * associated messages. The client prepares all necessary messages (depending on server's previous
   * flight) and returns the next flight.
   *
   * @return the client's next flight to be sent.
   * @throws HandshakeException
   */
  private DTLSFlight receivedServerHelloDone(ServerHelloDone message) throws HandshakeException {
    DTLSFlight flight = new DTLSFlight();
    if (serverHelloDone != null && (serverHelloDone.getMessageSeq() == message.getMessageSeq())) {
      // discard duplicate message
      return flight;
    }
    serverHelloDone = message;

    /*
     * All possible handshake messages sent in this flight. Used to compute
     * handshake hash.
     */
    CertificateMessage clientCertificate = null;
    ClientKeyExchange clientKeyExchange = null;
    CertificateVerify certificateVerify = null;

    /*
     * First, if required by server, send Certificate.
     */
    if (certificateRequest != null) {
      // TODO load the client's certificate according to the allowed
      // parameters in the CertificateRequest
      clientCertificate = new CertificateMessage(certificates, session.sendRawPublicKey());

      flight.addMessage(wrapMessage(clientCertificate));
    }

    /*
     * Second, send ClientKeyExchange as specified by the key exchange
     * algorithm.
     */
    byte[] premasterSecret;
    switch (keyExchange) {
      case EC_DIFFIE_HELLMAN:
        clientKeyExchange = new ECDHClientKeyExchange(ecdhe.getPublicKey());
        premasterSecret = ecdhe.getSecret(ephemeralServerPublicKey).getEncoded();

        generateKeys(premasterSecret);

        break;

      case PSK:
        String identity = ScProperties.std.getProperty("PSK_IDENTITY");
        clientKeyExchange = new PSKClientKeyExchange(identity);
        byte[] psk = sharedKeys.get(identity);

        if (psk == null) {
          AlertMessage alert =
              new AlertMessage(AlertLevel.FATAL, AlertDescription.HANDSHAKE_FAILURE);
          throw new HandshakeException(
              "No preshared secret found for identity: " + identity, alert);
        }

        LOGGER.info("Using PSK identity: " + identity);

        premasterSecret = generatePremasterSecretFromPSK(psk);
        generateKeys(premasterSecret);

        break;

      case NULL:
        clientKeyExchange = new NULLClientKeyExchange();

        // We assume, that the premaster secret is empty
        generateKeys(new byte[] {});
        break;

      default:
        AlertMessage alert = new AlertMessage(AlertLevel.FATAL, AlertDescription.HANDSHAKE_FAILURE);
        throw new HandshakeException("Unknown key exchange algorithm: " + keyExchange, alert);
    }
    flight.addMessage(wrapMessage(clientKeyExchange));

    /*
     * Third, send CertificateVerify message if necessary.
     */
    if (certificateRequest != null) {
      // prepare handshake messages
      handshakeMessages = ByteArrayUtils.concatenate(handshakeMessages, clientHello.toByteArray());
      handshakeMessages = ByteArrayUtils.concatenate(handshakeMessages, serverHello.toByteArray());
      handshakeMessages =
          ByteArrayUtils.concatenate(handshakeMessages, serverCertificate.toByteArray());
      handshakeMessages =
          ByteArrayUtils.concatenate(handshakeMessages, serverKeyExchange.toByteArray());
      handshakeMessages =
          ByteArrayUtils.concatenate(handshakeMessages, certificateRequest.toByteArray());
      handshakeMessages =
          ByteArrayUtils.concatenate(handshakeMessages, serverHelloDone.toByteArray());
      handshakeMessages =
          ByteArrayUtils.concatenate(handshakeMessages, clientCertificate.toByteArray());
      handshakeMessages =
          ByteArrayUtils.concatenate(handshakeMessages, clientKeyExchange.toByteArray());

      // TODO make sure, that signature is supported
      SignatureAndHashAlgorithm signatureAndHashAlgorithm =
          certificateRequest.getSupportedSignatureAlgorithms().get(0);
      certificateVerify =
          new CertificateVerify(signatureAndHashAlgorithm, privateKey, handshakeMessages);

      flight.addMessage(wrapMessage(certificateVerify));
    }

    /*
     * Fourth, send ChangeCipherSpec
     */
    ChangeCipherSpecMessage changeCipherSpecMessage = new ChangeCipherSpecMessage();
    flight.addMessage(wrapMessage(changeCipherSpecMessage));
    setCurrentWriteState();
    session.incrementWriteEpoch();

    /*
     * Fifth, send the finished message.
     */
    try {
      // create hash of handshake messages
      // can't do this on the fly, since there is no explicit ordering of
      // messages

      MessageDigest md = MessageDigest.getInstance("SHA-256");
      md.update(clientHello.toByteArray());
      md.update(serverHello.toByteArray());
      if (serverCertificate != null) {
        md.update(serverCertificate.toByteArray());
      }
      if (serverKeyExchange != null) {
        md.update(serverKeyExchange.toByteArray());
      }
      if (certificateRequest != null) {
        md.update(certificateRequest.toByteArray());
      }
      md.update(serverHelloDone.toByteArray());

      if (clientCertificate != null) {
        md.update(clientCertificate.toByteArray());
      }
      md.update(clientKeyExchange.toByteArray());

      if (certificateVerify != null) {
        md.update(certificateVerify.toByteArray());
      }

      MessageDigest mdWithClientFinished = null;
      try {
        mdWithClientFinished = (MessageDigest) md.clone();
      } catch (CloneNotSupportedException e) {
        LOGGER.severe("Clone not supported.");
        e.printStackTrace();
      }

      handshakeHash = md.digest();
      Finished finished = new Finished(getMasterSecret(), isClient, handshakeHash);
      flight.addMessage(wrapMessage(finished));

      // compute handshake hash with client's finished message also
      // included, used for server's finished message
      mdWithClientFinished.update(finished.toByteArray());
      handshakeHash = mdWithClientFinished.digest();

    } catch (NoSuchAlgorithmException e) {
      LOGGER.severe("No such Message Digest Algorithm available.");
      e.printStackTrace();
    }

    return flight;
  }