Example #1
0
  @SuppressWarnings("deprecation")
  private byte[] extractKeyData(DerInputStream stream)
      throws IOException, NoSuchAlgorithmException, CertificateException {
    byte[] returnValue = null;
    DerValue[] safeBags = stream.getSequence(2);
    int count = safeBags.length;

    /*
     * Spin over the SafeBags.
     */
    for (int i = 0; i < count; i++) {
      ObjectIdentifier bagId;
      DerInputStream sbi;
      DerValue bagValue;
      Object bagItem = null;

      sbi = safeBags[i].toDerInputStream();
      bagId = sbi.getOID();
      bagValue = sbi.getDerValue();
      if (!bagValue.isContextSpecific((byte) 0)) {
        throw new IOException("unsupported PKCS12 bag value type " + bagValue.tag);
      }
      bagValue = bagValue.data.getDerValue();
      if (bagId.equals(PKCS8ShroudedKeyBag_OID)) {
        // got what we were looking for.  Return it.
        returnValue = bagValue.toByteArray();
      } else {
        // log error message for "unsupported PKCS12 bag type"
        System.out.println("Unsupported bag type '" + bagId + "'");
      }
    }

    return returnValue;
  }
Example #2
0
  @SuppressWarnings("deprecation")
  private byte[] fetchPrivateKeyFromBag(byte[] privateKeyInfo)
      throws IOException, NoSuchAlgorithmException, CertificateException {
    byte[] returnValue = null;
    DerValue val = new DerValue(new ByteArrayInputStream(privateKeyInfo));
    DerInputStream s = val.toDerInputStream();
    int version = s.getInteger();

    if (version != 3) {
      throw new IOException("PKCS12 keystore not in version 3 format");
    }

    /*
     * Read the authSafe.
     */
    byte[] authSafeData;
    ContentInfo authSafe = new ContentInfo(s);
    ObjectIdentifier contentType = authSafe.getContentType();

    if (contentType.equals(ContentInfo.DATA_OID)) {
      authSafeData = authSafe.getData();
    } else /* signed data */ {
      throw new IOException("public key protected PKCS12 not supported");
    }

    DerInputStream as = new DerInputStream(authSafeData);
    DerValue[] safeContentsArray = as.getSequence(2);
    int count = safeContentsArray.length;

    /*
     * Spin over the ContentInfos.
     */
    for (int i = 0; i < count; i++) {
      byte[] safeContentsData;
      ContentInfo safeContents;
      DerInputStream sci;
      byte[] eAlgId = null;

      sci = new DerInputStream(safeContentsArray[i].toByteArray());
      safeContents = new ContentInfo(sci);
      contentType = safeContents.getContentType();
      safeContentsData = null;

      if (contentType.equals(ContentInfo.DATA_OID)) {
        safeContentsData = safeContents.getData();
      } else if (contentType.equals(ContentInfo.ENCRYPTED_DATA_OID)) {
        // The password was used to export the private key from the keychain.
        // The Keychain won't export the key with encrypted data, so we don't need
        // to worry about it.
        continue;
      } else {
        throw new IOException("public key protected PKCS12" + " not supported");
      }
      DerInputStream sc = new DerInputStream(safeContentsData);
      returnValue = extractKeyData(sc);
    }

    return returnValue;
  }
Example #3
0
 /*
  * parse Algorithm Parameters
  */
 private AlgorithmParameters parseAlgParameters(DerInputStream in) throws IOException {
   AlgorithmParameters algParams = null;
   try {
     DerValue params;
     if (in.available() == 0) {
       params = null;
     } else {
       params = in.getDerValue();
       if (params.tag == DerValue.tag_Null) {
         params = null;
       }
     }
     if (params != null) {
       algParams = AlgorithmParameters.getInstance("PBE");
       algParams.init(params.toByteArray());
     }
   } catch (Exception e) {
     IOException ioe = new IOException("parseAlgParameters failed: " + e.getMessage());
     ioe.initCause(e);
     throw ioe;
   }
   return algParams;
 }
Example #4
0
  /**
   * Returns the key associated with the given alias, using the given password to recover it.
   *
   * @param alias the alias name
   * @param password the password for recovering the key. This password is used internally as the
   *     key is exported in a PKCS12 format.
   * @return the requested key, or null if the given alias does not exist or does not identify a
   *     <i>key entry</i>.
   * @exception NoSuchAlgorithmException if the algorithm for recovering the key cannot be found
   * @exception UnrecoverableKeyException if the key cannot be recovered (e.g., the given password
   *     is wrong).
   */
  public Key engineGetKey(String alias, char[] password)
      throws NoSuchAlgorithmException, UnrecoverableKeyException {
    permissionCheck();

    // An empty password is rejected by MacOS API, no private key data
    // is exported. If no password is passed (as is the case when
    // this implementation is used as browser keystore in various
    // deployment scenarios like Webstart, JFX and applets), create
    // a dummy password so MacOS API is happy.
    if (password == null || password.length == 0) {
      // Must not be a char array with only a 0, as this is an empty
      // string.
      if (random == null) {
        random = new SecureRandom();
      }
      password = Long.toString(random.nextLong()).toCharArray();
    }

    Object entry = entries.get(alias.toLowerCase());

    if (entry == null || !(entry instanceof KeyEntry)) {
      return null;
    }

    // This call gives us a PKCS12 bag, with the key inside it.
    byte[] exportedKeyInfo = _getEncodedKeyData(((KeyEntry) entry).keyRef, password);
    if (exportedKeyInfo == null) {
      return null;
    }

    PrivateKey returnValue = null;

    try {
      byte[] pkcs8KeyData = fetchPrivateKeyFromBag(exportedKeyInfo);
      byte[] encryptedKey;
      AlgorithmParameters algParams;
      ObjectIdentifier algOid;
      try {
        // get the encrypted private key
        EncryptedPrivateKeyInfo encrInfo = new EncryptedPrivateKeyInfo(pkcs8KeyData);
        encryptedKey = encrInfo.getEncryptedData();

        // parse Algorithm parameters
        DerValue val = new DerValue(encrInfo.getAlgorithm().encode());
        DerInputStream in = val.toDerInputStream();
        algOid = in.getOID();
        algParams = parseAlgParameters(in);

      } catch (IOException ioe) {
        UnrecoverableKeyException uke =
            new UnrecoverableKeyException(
                "Private key not stored as " + "PKCS#8 EncryptedPrivateKeyInfo: " + ioe);
        uke.initCause(ioe);
        throw uke;
      }

      // Use JCE to decrypt the data using the supplied password.
      SecretKey skey = getPBEKey(password);
      Cipher cipher = Cipher.getInstance(algOid.toString());
      cipher.init(Cipher.DECRYPT_MODE, skey, algParams);
      byte[] decryptedPrivateKey = cipher.doFinal(encryptedKey);
      PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(decryptedPrivateKey);

      // Parse the key algorithm and then use a JCA key factory to create the private key.
      DerValue val = new DerValue(decryptedPrivateKey);
      DerInputStream in = val.toDerInputStream();

      // Ignore this -- version should be 0.
      int i = in.getInteger();

      // Get the Algorithm ID next
      DerValue[] value = in.getSequence(2);
      AlgorithmId algId = new AlgorithmId(value[0].getOID());
      String algName = algId.getName();

      // Get a key factory for this algorithm.  It's likely to be 'RSA'.
      KeyFactory kfac = KeyFactory.getInstance(algName);
      returnValue = kfac.generatePrivate(kspec);
    } catch (Exception e) {
      UnrecoverableKeyException uke =
          new UnrecoverableKeyException("Get Key failed: " + e.getMessage());
      uke.initCause(e);
      throw uke;
    }

    return returnValue;
  }
    private SingleResponse(DerValue der) throws IOException {
      if (der.tag != DerValue.tag_Sequence) {
        throw new IOException("Bad ASN.1 encoding in SingleResponse");
      }
      DerInputStream tmp = der.data;

      certId = new CertId(tmp.getDerValue().data);
      DerValue derVal = tmp.getDerValue();
      short tag = (byte) (derVal.tag & 0x1f);
      if (tag == CERT_STATUS_REVOKED) {
        certStatus = CertStatus.REVOKED;
        revocationTime = derVal.data.getGeneralizedTime();
        if (derVal.data.available() != 0) {
          DerValue dv = derVal.data.getDerValue();
          tag = (byte) (dv.tag & 0x1f);
          if (tag == 0) {
            int reason = dv.data.getEnumerated();
            // if reason out-of-range just leave as UNSPECIFIED
            if (reason >= 0 && reason < values.length) {
              revocationReason = values[reason];
            } else {
              revocationReason = CRLReason.UNSPECIFIED;
            }
          } else {
            revocationReason = CRLReason.UNSPECIFIED;
          }
        } else {
          revocationReason = CRLReason.UNSPECIFIED;
        }
        // RevokedInfo
        if (debug != null) {
          debug.println("Revocation time: " + revocationTime);
          debug.println("Revocation reason: " + revocationReason);
        }
      } else {
        revocationTime = null;
        revocationReason = CRLReason.UNSPECIFIED;
        if (tag == CERT_STATUS_GOOD) {
          certStatus = CertStatus.GOOD;
        } else if (tag == CERT_STATUS_UNKNOWN) {
          certStatus = CertStatus.UNKNOWN;
        } else {
          throw new IOException("Invalid certificate status");
        }
      }

      thisUpdate = tmp.getGeneralizedTime();

      if (tmp.available() == 0) {
        // we are done
        nextUpdate = null;
      } else {
        derVal = tmp.getDerValue();
        tag = (byte) (derVal.tag & 0x1f);
        if (tag == 0) {
          // next update
          nextUpdate = derVal.data.getGeneralizedTime();

          if (tmp.available() == 0) {
            // we are done
          } else {
            derVal = tmp.getDerValue();
            tag = (byte) (derVal.tag & 0x1f);
          }
        } else {
          nextUpdate = null;
        }
      }
      // singleExtensions
      if (tmp.available() > 0) {
        derVal = tmp.getDerValue();
        if (derVal.isContextSpecific((byte) 1)) {
          DerValue[] singleExtDer = derVal.data.getSequence(3);
          singleExtensions = new HashMap<String, java.security.cert.Extension>(singleExtDer.length);
          for (int i = 0; i < singleExtDer.length; i++) {
            Extension ext = new Extension(singleExtDer[i]);
            if (debug != null) {
              debug.println("OCSP single extension: " + ext);
            }
            // We don't support any extensions yet. Therefore, if it
            // is critical we must throw an exception because we
            // don't know how to process it.
            if (ext.isCritical()) {
              throw new IOException("Unsupported OCSP critical extension: " + ext.getExtensionId());
            }
            singleExtensions.put(ext.getId(), ext);
          }
        } else {
          singleExtensions = Collections.emptyMap();
        }
      } else {
        singleExtensions = Collections.emptyMap();
      }
    }
  /*
   * Create an OCSP response from its ASN.1 DER encoding.
   */
  OCSPResponse(byte[] bytes) throws IOException {
    if (dump) {
      HexDumpEncoder hexEnc = new HexDumpEncoder();
      System.out.println("OCSPResponse bytes are...");
      System.out.println(hexEnc.encode(bytes));
    }
    DerValue der = new DerValue(bytes);
    if (der.tag != DerValue.tag_Sequence) {
      throw new IOException("Bad encoding in OCSP response: " + "expected ASN.1 SEQUENCE tag.");
    }
    DerInputStream derIn = der.getData();

    // responseStatus
    int status = derIn.getEnumerated();
    if (status >= 0 && status < rsvalues.length) {
      responseStatus = rsvalues[status];
    } else {
      // unspecified responseStatus
      throw new IOException("Unknown OCSPResponse status: " + status);
    }
    if (debug != null) {
      debug.println("OCSP response status: " + responseStatus);
    }
    if (responseStatus != ResponseStatus.SUCCESSFUL) {
      // no need to continue, responseBytes are not set.
      singleResponseMap = Collections.emptyMap();
      certs = Collections.<X509CertImpl>emptyList();
      sigAlgId = null;
      signature = null;
      tbsResponseData = null;
      responseNonce = null;
      return;
    }

    // responseBytes
    der = derIn.getDerValue();
    if (!der.isContextSpecific((byte) 0)) {
      throw new IOException(
          "Bad encoding in responseBytes element "
              + "of OCSP response: expected ASN.1 context specific tag 0.");
    }
    DerValue tmp = der.data.getDerValue();
    if (tmp.tag != DerValue.tag_Sequence) {
      throw new IOException(
          "Bad encoding in responseBytes element "
              + "of OCSP response: expected ASN.1 SEQUENCE tag.");
    }

    // responseType
    derIn = tmp.data;
    ObjectIdentifier responseType = derIn.getOID();
    if (responseType.equals((Object) OCSP_BASIC_RESPONSE_OID)) {
      if (debug != null) {
        debug.println("OCSP response type: basic");
      }
    } else {
      if (debug != null) {
        debug.println("OCSP response type: " + responseType);
      }
      throw new IOException("Unsupported OCSP response type: " + responseType);
    }

    // BasicOCSPResponse
    DerInputStream basicOCSPResponse = new DerInputStream(derIn.getOctetString());

    DerValue[] seqTmp = basicOCSPResponse.getSequence(2);
    if (seqTmp.length < 3) {
      throw new IOException("Unexpected BasicOCSPResponse value");
    }

    DerValue responseData = seqTmp[0];

    // Need the DER encoded ResponseData to verify the signature later
    tbsResponseData = seqTmp[0].toByteArray();

    // tbsResponseData
    if (responseData.tag != DerValue.tag_Sequence) {
      throw new IOException(
          "Bad encoding in tbsResponseData "
              + "element of OCSP response: expected ASN.1 SEQUENCE tag.");
    }
    DerInputStream seqDerIn = responseData.data;
    DerValue seq = seqDerIn.getDerValue();

    // version
    if (seq.isContextSpecific((byte) 0)) {
      // seq[0] is version
      if (seq.isConstructed() && seq.isContextSpecific()) {
        // System.out.println ("version is available");
        seq = seq.data.getDerValue();
        int version = seq.getInteger();
        if (seq.data.available() != 0) {
          throw new IOException(
              "Bad encoding in version " + " element of OCSP response: bad format");
        }
        seq = seqDerIn.getDerValue();
      }
    }

    // responderID
    short tag = (byte) (seq.tag & 0x1f);
    if (tag == NAME_TAG) {
      if (debug != null) {
        X500Principal responderName = new X500Principal(seq.getData().toByteArray());
        debug.println("OCSP Responder name: " + responderName);
      }
    } else if (tag == KEY_TAG) {
      if (debug != null) {
        byte[] responderKey = seq.getData().getOctetString();
        debug.println("OCSP Responder key: " + Debug.toString(responderKey));
      }
    } else {
      throw new IOException(
          "Bad encoding in responderID element of "
              + "OCSP response: expected ASN.1 context specific tag 0 or 1");
    }

    // producedAt
    seq = seqDerIn.getDerValue();
    if (debug != null) {
      Date producedAtDate = seq.getGeneralizedTime();
      debug.println("OCSP response produced at: " + producedAtDate);
    }

    // responses
    DerValue[] singleResponseDer = seqDerIn.getSequence(1);
    singleResponseMap = new HashMap<>(singleResponseDer.length);
    if (debug != null) {
      debug.println("OCSP number of SingleResponses: " + singleResponseDer.length);
    }
    for (int i = 0; i < singleResponseDer.length; i++) {
      SingleResponse singleResponse = new SingleResponse(singleResponseDer[i]);
      singleResponseMap.put(singleResponse.getCertId(), singleResponse);
    }

    // responseExtensions
    byte[] nonce = null;
    if (seqDerIn.available() > 0) {
      seq = seqDerIn.getDerValue();
      if (seq.isContextSpecific((byte) 1)) {
        DerValue[] responseExtDer = seq.data.getSequence(3);
        for (int i = 0; i < responseExtDer.length; i++) {
          Extension ext = new Extension(responseExtDer[i]);
          if (debug != null) {
            debug.println("OCSP extension: " + ext);
          }
          // Only the NONCE extension is recognized
          if (ext.getExtensionId().equals((Object) OCSP.NONCE_EXTENSION_OID)) {
            nonce = ext.getExtensionValue();
          } else if (ext.isCritical()) {
            throw new IOException("Unsupported OCSP critical extension: " + ext.getExtensionId());
          }
        }
      }
    }
    responseNonce = nonce;

    // signatureAlgorithmId
    sigAlgId = AlgorithmId.parse(seqTmp[1]);

    // signature
    signature = seqTmp[2].getBitString();

    // if seq[3] is available , then it is a sequence of certificates
    if (seqTmp.length > 3) {
      // certs are available
      DerValue seqCert = seqTmp[3];
      if (!seqCert.isContextSpecific((byte) 0)) {
        throw new IOException(
            "Bad encoding in certs element of "
                + "OCSP response: expected ASN.1 context specific tag 0.");
      }
      DerValue[] derCerts = seqCert.getData().getSequence(3);
      certs = new ArrayList<X509CertImpl>(derCerts.length);
      try {
        for (int i = 0; i < derCerts.length; i++) {
          certs.add(new X509CertImpl(derCerts[i].toByteArray()));
        }
      } catch (CertificateException ce) {
        throw new IOException("Bad encoding in X509 Certificate", ce);
      }
    } else {
      certs = Collections.<X509CertImpl>emptyList();
    }
  }