/** Creates a new TlsSocketFactory */
  public TlsSocketFactory(TlsContext tls_context)
      throws java.security.KeyStoreException, java.security.KeyManagementException,
          java.security.UnrecoverableKeyException, java.security.NoSuchAlgorithmException {
    KeyStore ks = tls_context.getKeyStore();
    // get key managers
    KeyManagerFactory key_manager_factory =
        KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    key_manager_factory.init(ks, TlsContext.DEFAULT_PASSWORD);
    KeyManager[] key_managers = key_manager_factory.getKeyManagers();
    TrustManager[] trust_managers;
    // get trust managers
    if (tls_context.isTrustAll()) {
      X509TrustManager trust_all =
          new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
              return new X509Certificate[0];
            }

            public void checkClientTrusted(X509Certificate[] certs, String auth_type) {}

            public void checkServerTrusted(X509Certificate[] certs, String auth_type) {}
          };
      trust_managers = new TrustManager[] {trust_all};
    } else {
      TrustManagerFactory trust_manager_factory =
          TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
      trust_manager_factory.init(ks);
      trust_managers = trust_manager_factory.getTrustManagers();
    }
    // install only the trust managers
    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(key_managers, trust_managers, null /*new java.security.SecureRandom()*/);
    // get the socket factory
    ssl_factory = sc.getSocketFactory();
  }
  /**
   * Initializes a new <tt>SRTPTransformer</tt> instance with a specific (negotiated)
   * <tt>SRTPProtectionProfile</tt> and the keying material specified by a specific
   * <tt>TlsContext</tt>.
   *
   * @param srtpProtectionProfile the (negotiated) <tt>SRTPProtectionProfile</tt> to initialize the
   *     new instance with
   * @param tlsContext the <tt>TlsContext</tt> which represents the keying material
   * @return a new <tt>SRTPTransformer</tt> instance initialized with <tt>srtpProtectionProfile</tt>
   *     and <tt>tlsContext</tt>
   */
  private SinglePacketTransformer initializeSRTPTransformer(
      int srtpProtectionProfile, TlsContext tlsContext) {
    boolean rtcp;

    switch (componentID) {
      case Component.RTCP:
        rtcp = true;
        break;
      case Component.RTP:
        rtcp = false;
        break;
      default:
        throw new IllegalStateException("componentID");
    }

    int cipher_key_length;
    int cipher_salt_length;
    int cipher;
    int auth_function;
    int auth_key_length;
    int RTCP_auth_tag_length, RTP_auth_tag_length;

    switch (srtpProtectionProfile) {
      case SRTPProtectionProfile.SRTP_AES128_CM_HMAC_SHA1_32:
        cipher_key_length = 128 / 8;
        cipher_salt_length = 112 / 8;
        cipher = SRTPPolicy.AESCM_ENCRYPTION;
        auth_function = SRTPPolicy.HMACSHA1_AUTHENTICATION;
        auth_key_length = 160 / 8;
        RTCP_auth_tag_length = 80 / 8;
        RTP_auth_tag_length = 32 / 8;
        break;
      case SRTPProtectionProfile.SRTP_AES128_CM_HMAC_SHA1_80:
        cipher_key_length = 128 / 8;
        cipher_salt_length = 112 / 8;
        cipher = SRTPPolicy.AESCM_ENCRYPTION;
        auth_function = SRTPPolicy.HMACSHA1_AUTHENTICATION;
        auth_key_length = 160 / 8;
        RTCP_auth_tag_length = RTP_auth_tag_length = 80 / 8;
        break;
      case SRTPProtectionProfile.SRTP_NULL_HMAC_SHA1_32:
        cipher_key_length = 0;
        cipher_salt_length = 0;
        cipher = SRTPPolicy.NULL_ENCRYPTION;
        auth_function = SRTPPolicy.HMACSHA1_AUTHENTICATION;
        auth_key_length = 160 / 8;
        RTCP_auth_tag_length = 80 / 8;
        RTP_auth_tag_length = 32 / 8;
        break;
      case SRTPProtectionProfile.SRTP_NULL_HMAC_SHA1_80:
        cipher_key_length = 0;
        cipher_salt_length = 0;
        cipher = SRTPPolicy.NULL_ENCRYPTION;
        auth_function = SRTPPolicy.HMACSHA1_AUTHENTICATION;
        auth_key_length = 160 / 8;
        RTCP_auth_tag_length = RTP_auth_tag_length = 80 / 8;
        break;
      default:
        throw new IllegalArgumentException("srtpProtectionProfile");
    }

    byte[] keyingMaterial =
        tlsContext.exportKeyingMaterial(
            ExporterLabel.dtls_srtp, null, 2 * (cipher_key_length + cipher_salt_length));
    byte[] client_write_SRTP_master_key = new byte[cipher_key_length];
    byte[] server_write_SRTP_master_key = new byte[cipher_key_length];
    byte[] client_write_SRTP_master_salt = new byte[cipher_salt_length];
    byte[] server_write_SRTP_master_salt = new byte[cipher_salt_length];
    byte[][] keyingMaterialValues = {
      client_write_SRTP_master_key,
      server_write_SRTP_master_key,
      client_write_SRTP_master_salt,
      server_write_SRTP_master_salt
    };

    for (int i = 0, keyingMaterialOffset = 0; i < keyingMaterialValues.length; i++) {
      byte[] keyingMaterialValue = keyingMaterialValues[i];

      System.arraycopy(
          keyingMaterial, keyingMaterialOffset, keyingMaterialValue, 0, keyingMaterialValue.length);
      keyingMaterialOffset += keyingMaterialValue.length;
    }

    SRTPPolicy srtcpPolicy =
        new SRTPPolicy(
            cipher,
            cipher_key_length,
            auth_function,
            auth_key_length,
            RTCP_auth_tag_length,
            cipher_salt_length);
    SRTPPolicy srtpPolicy =
        new SRTPPolicy(
            cipher,
            cipher_key_length,
            auth_function,
            auth_key_length,
            RTP_auth_tag_length,
            cipher_salt_length);
    SRTPContextFactory clientSRTPContextFactory =
        new SRTPContextFactory(
            /* sender */ tlsContext instanceof TlsClientContext,
            client_write_SRTP_master_key,
            client_write_SRTP_master_salt,
            srtpPolicy,
            srtcpPolicy);
    SRTPContextFactory serverSRTPContextFactory =
        new SRTPContextFactory(
            /* sender */ tlsContext instanceof TlsServerContext,
            server_write_SRTP_master_key,
            server_write_SRTP_master_salt,
            srtpPolicy,
            srtcpPolicy);
    SRTPContextFactory forwardSRTPContextFactory;
    SRTPContextFactory reverseSRTPContextFactory;

    if (tlsContext instanceof TlsClientContext) {
      forwardSRTPContextFactory = clientSRTPContextFactory;
      reverseSRTPContextFactory = serverSRTPContextFactory;
    } else if (tlsContext instanceof TlsServerContext) {
      forwardSRTPContextFactory = serverSRTPContextFactory;
      reverseSRTPContextFactory = clientSRTPContextFactory;
    } else {
      throw new IllegalArgumentException("tlsContext");
    }

    SinglePacketTransformer srtpTransformer;

    if (rtcp) {
      srtpTransformer = new SRTCPTransformer(forwardSRTPContextFactory, reverseSRTPContextFactory);
    } else {
      srtpTransformer = new SRTPTransformer(forwardSRTPContextFactory, reverseSRTPContextFactory);
    }
    return srtpTransformer;
  }
  public void init(TlsContext context) {
    this.context = context;

    ProtocolVersion clientVersion = context.getClientVersion();

    if (TlsUtils.isSignatureAlgorithmsExtensionAllowed(clientVersion)) {
      /*
       * RFC 5264 7.4.1.4.1. If the client does not send the signature_algorithms extension,
       * the server MUST do the following:
       *
       * - If the negotiated key exchange algorithm is one of (RSA, DHE_RSA, DH_RSA, RSA_PSK,
       * ECDH_RSA, ECDHE_RSA), behave as if client had sent the value {sha1,rsa}.
       *
       * - If the negotiated key exchange algorithm is one of (DHE_DSS, DH_DSS), behave as if
       * the client had sent the value {sha1,dsa}.
       *
       * - If the negotiated key exchange algorithm is one of (ECDH_ECDSA, ECDHE_ECDSA),
       * behave as if the client had sent value {sha1,ecdsa}.
       */
      if (this.supportedSignatureAlgorithms == null) {
        switch (keyExchange) {
          case KeyExchangeAlgorithm.DH_DSS:
          case KeyExchangeAlgorithm.DHE_DSS:
          case KeyExchangeAlgorithm.SRP_DSS:
            {
              this.supportedSignatureAlgorithms = TlsUtils.getDefaultDSSSignatureAlgorithms();
              break;
            }

          case KeyExchangeAlgorithm.ECDH_ECDSA:
          case KeyExchangeAlgorithm.ECDHE_ECDSA:
            {
              this.supportedSignatureAlgorithms = TlsUtils.getDefaultECDSASignatureAlgorithms();
              break;
            }

          case KeyExchangeAlgorithm.DH_RSA:
          case KeyExchangeAlgorithm.DHE_RSA:
          case KeyExchangeAlgorithm.ECDH_RSA:
          case KeyExchangeAlgorithm.ECDHE_RSA:
          case KeyExchangeAlgorithm.RSA:
          case KeyExchangeAlgorithm.RSA_PSK:
          case KeyExchangeAlgorithm.SRP_RSA:
            {
              this.supportedSignatureAlgorithms = TlsUtils.getDefaultRSASignatureAlgorithms();
              break;
            }

          case KeyExchangeAlgorithm.DHE_PSK:
          case KeyExchangeAlgorithm.ECDHE_PSK:
          case KeyExchangeAlgorithm.PSK:
          case KeyExchangeAlgorithm.SRP:
            break;

          default:
            throw new IllegalStateException("unsupported key exchange algorithm");
        }
      }
    } else if (this.supportedSignatureAlgorithms != null) {
      throw new IllegalStateException(
          "supported_signature_algorithms not allowed for " + clientVersion);
    }
  }