/** * Add an attribute to the section * * @param attribute the attribute to be added. * @return the value of the attribute if it is a name attribute - null other wise * @throws ManifestException if the attribute already exists in this section. */ public String addAttributeAndCheck(Attribute attribute) throws ManifestException { if (attribute.getName() == null || attribute.getValue() == null) { throw new ManifestException("Attributes must have name and value"); } if (attribute.getKey().equalsIgnoreCase(ATTRIBUTE_NAME)) { warnings.addElement( "\"" + ATTRIBUTE_NAME + "\" attributes " + "should not occur in the main section and must be the " + "first element in all other sections: \"" + attribute.getName() + ": " + attribute.getValue() + "\""); return attribute.getValue(); } if (attribute.getKey().startsWith(ATTRIBUTE_FROM.toLowerCase())) { warnings.addElement( "Manifest attributes should not start " + "with \"" + ATTRIBUTE_FROM + "\" in \"" + attribute.getName() + ": " + attribute.getValue() + "\""); } else { // classpath attributes go into a vector String attributeKey = attribute.getKey(); if (attributeKey.equalsIgnoreCase(ATTRIBUTE_CLASSPATH)) { Attribute classpathAttribute = (Attribute) attributes.get(attributeKey); if (classpathAttribute == null) { storeAttribute(attribute); } else { warnings.addElement( "Multiple Class-Path attributes " + "are supported but violate the Jar " + "specification and may not be correctly " + "processed in all environments"); Enumeration e = attribute.getValues(); while (e.hasMoreElements()) { String value = (String) e.nextElement(); classpathAttribute.addValue(value); } } } else if (attributes.containsKey(attributeKey)) { throw new ManifestException( "The attribute \"" + attribute.getName() + "\" may not occur more " + "than once in the same section"); } else { storeAttribute(attribute); } } return null; }
/** * Merge in another section * * @param section the section to be merged with this one. * @throws ManifestException if the sections cannot be merged. */ public void merge(Section section) throws ManifestException { if (name == null && section.getName() != null || name != null && !(name.equalsIgnoreCase(section.getName()))) { throw new ManifestException("Unable to merge sections with different names"); } Enumeration e = section.getAttributeKeys(); Attribute classpathAttribute = null; while (e.hasMoreElements()) { String attributeName = (String) e.nextElement(); Attribute attribute = section.getAttribute(attributeName); if (attributeName.equalsIgnoreCase(ATTRIBUTE_CLASSPATH)) { if (classpathAttribute == null) { classpathAttribute = new Attribute(); classpathAttribute.setName(ATTRIBUTE_CLASSPATH); } Enumeration cpe = attribute.getValues(); while (cpe.hasMoreElements()) { String value = (String) cpe.nextElement(); classpathAttribute.addValue(value); } } else { // the merge file always wins storeAttribute(attribute); } } if (classpathAttribute != null) { // the merge file *always* wins, even for Class-Path storeAttribute(classpathAttribute); } // add in the warnings Enumeration warnEnum = section.warnings.elements(); while (warnEnum.hasMoreElements()) { warnings.addElement(warnEnum.nextElement()); } }
public static void main(String[] args) { try { // Read arguments if (args.length != 3) { System.out.println("Usage: PFX <dbdir> <infile> <outfile>"); System.exit(-1); } // open input file for reading FileInputStream infile = null; try { infile = new FileInputStream(args[1]); } catch (FileNotFoundException f) { System.out.println("Cannot open file " + args[1] + " for reading: " + f.getMessage()); return; } int certfile = 0; // initialize CryptoManager. This is necessary because there is // crypto involved with decoding a PKCS #12 file CryptoManager.initialize(args[0]); CryptoManager manager = CryptoManager.getInstance(); // Decode the P12 file PFX.Template pfxt = new PFX.Template(); PFX pfx = (PFX) pfxt.decode(new BufferedInputStream(infile, 2048)); System.out.println("Decoded PFX"); // print out information about the top-level PFX structure System.out.println("Version: " + pfx.getVersion()); AuthenticatedSafes authSafes = pfx.getAuthSafes(); SEQUENCE safeContentsSequence = authSafes.getSequence(); System.out.println("AuthSafes has " + safeContentsSequence.size() + " SafeContents"); // Get the password for the old file System.out.println("Enter password: "******"Enter new password:"******"AuthSafes verifies correctly."); } else { System.out.println("AuthSafes failed to verify because: " + sb); } // Create a new AuthenticatedSafes. As we read the contents of the // old authSafes, we will store them into the new one. After we have // cycled through all the contents, they will all have been copied into // the new authSafes. AuthenticatedSafes newAuthSafes = new AuthenticatedSafes(); // Loop over contents of the old authenticated safes // for(int i=0; i < asSeq.size(); i++) { for (int i = 0; i < safeContentsSequence.size(); i++) { // The safeContents may or may not be encrypted. We always send // the password in. It will get used if it is needed. If the // decryption of the safeContents fails for some reason (like // a bad password), then this method will throw an exception SEQUENCE safeContents = authSafes.getSafeContentsAt(pass, i); System.out.println("\n\nSafeContents #" + i + " has " + safeContents.size() + " bags"); // Go through all the bags in this SafeContents for (int j = 0; j < safeContents.size(); j++) { SafeBag safeBag = (SafeBag) safeContents.elementAt(j); // The type of the bag is an OID System.out.println("\nBag " + j + " has type " + safeBag.getBagType()); // look for bag attributes SET attribs = safeBag.getBagAttributes(); if (attribs == null) { System.out.println("Bag has no attributes"); } else { for (int b = 0; b < attribs.size(); b++) { Attribute a = (Attribute) attribs.elementAt(b); if (a.getType().equals(SafeBag.FRIENDLY_NAME)) { // the friendly name attribute is a nickname BMPString bs = (BMPString) ((ANY) a.getValues().elementAt(0)).decodeWith(BMPString.getTemplate()); System.out.println("Friendly Name: " + bs); } else if (a.getType().equals(SafeBag.LOCAL_KEY_ID)) { // the local key id is used to match a key // to its cert. The key id is the SHA-1 hash of // the DER-encoded cert. OCTET_STRING os = (OCTET_STRING) ((ANY) a.getValues().elementAt(0)).decodeWith(OCTET_STRING.getTemplate()); System.out.println("LocalKeyID:"); /* AuthenticatedSafes. print_byte_array(os.toByteArray()); */ } else { System.out.println("Unknown attribute type: " + a.getType().toString()); } } } // now look at the contents of the bag ASN1Value val = safeBag.getInterpretedBagContent(); if (val instanceof PrivateKeyInfo) { // A PrivateKeyInfo contains an unencrypted private key System.out.println("content is PrivateKeyInfo"); } else if (val instanceof EncryptedPrivateKeyInfo) { // An EncryptedPrivateKeyInfo is, well, an encrypted // PrivateKeyInfo. Usually, strong crypto is used in // an EncryptedPrivateKeyInfo. EncryptedPrivateKeyInfo epki = ((EncryptedPrivateKeyInfo) val); System.out.println( "content is EncryptedPrivateKeyInfo, algoid:" + epki.getEncryptionAlgorithm().getOID()); // Because we are in a PKCS #12 file, the passwords are // char-to-byte converted in a special way. We have to // use the special converter class instead of the default. PrivateKeyInfo pki = epki.decrypt(pass, new org.mozilla.jss.pkcs12.PasswordConverter()); // import the key into the key3.db CryptoToken tok = manager.getTokenByName("Internal Key Storage Token"); CryptoStore store = tok.getCryptoStore(); tok.login(new ConsolePasswordCallback()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); pki.encode(baos); store.importPrivateKey(baos.toByteArray(), PrivateKey.RSA); // re-encrypt the PrivateKeyInfo with the new password // and random salt byte[] salt = new byte[PBEAlgorithm.PBE_SHA1_DES3_CBC.getSaltLength()]; JSSSecureRandom rand = CryptoManager.getInstance().getSecureRNG(); rand.nextBytes(salt); epki = EncryptedPrivateKeyInfo.createPBE( PBEAlgorithm.PBE_SHA1_DES3_CBC, newPass, salt, 1, new PasswordConverter(), pki); // Overwrite the previous EncryptedPrivateKeyInfo with // this new one we just created using the new password. // This is what will get put in the new PKCS #12 file // we are creating. safeContents.insertElementAt( new SafeBag(safeBag.getBagType(), epki, safeBag.getBagAttributes()), i); safeContents.removeElementAt(i + 1); } else if (val instanceof CertBag) { System.out.println("content is CertBag"); CertBag cb = (CertBag) val; if (cb.getCertType().equals(CertBag.X509_CERT_TYPE)) { // this is an X.509 certificate OCTET_STRING os = (OCTET_STRING) cb.getInterpretedCert(); Certificate cert = (Certificate) ASN1Util.decode(Certificate.getTemplate(), os.toByteArray()); cert.getInfo().print(System.out); } else { System.out.println("Unrecognized cert type"); } } else { System.out.println("content is ANY"); } } // Add the new safe contents to the new authsafes if (authSafes.safeContentsIsEncrypted(i)) { newAuthSafes.addEncryptedSafeContents( authSafes.DEFAULT_KEY_GEN_ALG, newPass, null, authSafes.DEFAULT_ITERATIONS, safeContents); } else { newAuthSafes.addSafeContents(safeContents); } } // Create new PFX from the new authsafes PFX newPfx = new PFX(newAuthSafes); // Add a MAC to the new PFX newPfx.computeMacData(newPass, null, PFX.DEFAULT_ITERATIONS); // write the new PFX out to a file FileOutputStream fos = new FileOutputStream(args[2]); newPfx.encode(fos); fos.close(); } catch (Exception e) { e.printStackTrace(); } }