1 13 14 package org.ejbca.core.protocol.xkms.common; 15 16 import gnu.inet.encoding.Stringprep; 17 import gnu.inet.encoding.StringprepException; 18 19 import java.io.UnsupportedEncodingException ; 20 import java.math.BigInteger ; 21 import java.security.InvalidKeyException ; 22 import java.security.KeyFactory ; 23 import java.security.NoSuchAlgorithmException ; 24 import java.security.PrivateKey ; 25 import java.security.interfaces.RSAPrivateCrtKey ; 26 import java.security.interfaces.RSAPrivateKey ; 27 import java.security.spec.InvalidKeySpecException ; 28 import java.security.spec.RSAPrivateCrtKeySpec ; 29 30 import javax.crypto.Mac; 31 import javax.crypto.SecretKey; 32 import javax.crypto.spec.SecretKeySpec; 33 import javax.xml.bind.JAXBContext; 34 import javax.xml.bind.JAXBElement; 35 import javax.xml.bind.JAXBException; 36 import javax.xml.bind.Marshaller; 37 import javax.xml.bind.PropertyException; 38 import javax.xml.bind.Unmarshaller; 39 import javax.xml.parsers.DocumentBuilder ; 40 import javax.xml.parsers.DocumentBuilderFactory ; 41 import javax.xml.parsers.ParserConfigurationException ; 42 43 import org.apache.log4j.Logger; 44 import org.apache.xml.security.algorithms.SignatureAlgorithm; 45 import org.apache.xml.security.encryption.EncryptedData; 46 import org.apache.xml.security.encryption.XMLCipher; 47 import org.apache.xml.security.encryption.XMLEncryptionException; 48 import org.apache.xml.security.exceptions.XMLSecurityException; 49 import org.apache.xml.security.transforms.Transforms; 50 import org.apache.xml.security.utils.EncryptionConstants; 51 import org.ejbca.util.CertTools; 52 import org.w3._2001._04.xmlenc_.EncryptedDataType; 53 import org.w3._2002._03.xkms_.ObjectFactory; 54 import org.w3._2002._03.xkms_.PrivateKeyType; 55 import org.w3._2002._03.xkms_.RSAKeyPairType; 56 import org.w3c.dom.Document ; 57 import org.w3c.dom.Element ; 58 59 68 69 public class XKMSUtil { 70 71 72 public static final byte[] KEY_AUTHENTICATION = {0x1}; 73 public static final byte[] KEY_REVOCATIONCODEIDENTIFIER_PASS1 = {0x2}; 74 public static final byte[] KEY_REVOCATIONCODEIDENTIFIER_PASS2 = {0x3}; 75 public static final byte[] KEY_PRIVATEKEYDATA = {0x4}; 76 77 private static final String ENCRYPTION_ALGORITHMURI = XMLCipher.TRIPLEDES; 78 private static final String SHAREDSECRET_HASH_ALGORITH = "http://www.w3.org/2000/09/xmldsig#hmac-sha1"; 79 80 private static Logger log = Logger.getLogger(XKMSUtil.class); 81 82 private static ObjectFactory xKMSObjectFactory = new ObjectFactory(); 83 84 private static JAXBContext jAXBContext = null; 85 private static Marshaller marshaller = null; 86 private static Unmarshaller unmarshaller = null; 87 private static DocumentBuilderFactory dbf = null; 88 89 static{ 90 try { 91 CertTools.installBCProvider(); 92 org.apache.xml.security.Init.init(); 93 94 jAXBContext = JAXBContext.newInstance("org.w3._2002._03.xkms_:org.w3._2001._04.xmlenc_:org.w3._2000._09.xmldsig_"); 95 marshaller = jAXBContext.createMarshaller(); 96 try { 97 marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper",new XKMSNamespacePrefixMapper()); 98 } catch( PropertyException e ) { 99 log.error("Error registering namespace mapper property",e); 100 } 101 dbf = DocumentBuilderFactory.newInstance(); 102 dbf.setNamespaceAware(true); 103 unmarshaller = jAXBContext.createUnmarshaller(); 104 105 } catch (JAXBException e) { 106 log.error("Error initializing RequestAbstractTypeResponseGenerator",e); 107 } 108 } 109 110 123 public static PrivateKeyType getEncryptedXMLFromPrivateKey(RSAPrivateCrtKey rSAPrivateKey, String sharedSecret) throws StringprepException, XMLEncryptionException{ 124 PrivateKeyType privateKeyType = null; 125 try{ 126 DocumentBuilder db = dbf.newDocumentBuilder(); 127 Document rSAKeyPairDoc = db.newDocument(); 128 129 SecretKey sk = getSecretKeyFromPassphrase(sharedSecret,true, 24, KEY_PRIVATEKEYDATA); 130 131 RSAKeyPairType rSAKeyPairType = xKMSObjectFactory.createRSAKeyPairType(); 132 133 rSAKeyPairType.setModulus(rSAPrivateKey.getModulus().toByteArray()); 134 rSAKeyPairType.setExponent(rSAPrivateKey.getPublicExponent().toByteArray()); 135 rSAKeyPairType.setP(rSAPrivateKey.getPrimeP().toByteArray()); 136 rSAKeyPairType.setQ(rSAPrivateKey.getPrimeQ().toByteArray()); 137 rSAKeyPairType.setDP(rSAPrivateKey.getPrimeExponentP().toByteArray()); 138 rSAKeyPairType.setDQ(rSAPrivateKey.getPrimeExponentQ().toByteArray()); 139 rSAKeyPairType.setInverseQ(rSAPrivateKey.getCrtCoefficient().toByteArray()); 140 rSAKeyPairType.setD(rSAPrivateKey.getPrivateExponent().toByteArray()); 141 142 JAXBElement<RSAKeyPairType> rSAKeyPair = xKMSObjectFactory.createRSAKeyPair(rSAKeyPairType); 143 144 marshaller.marshal( rSAKeyPair, rSAKeyPairDoc ); 145 146 Document envelopedDoc = db.newDocument(); 147 Element unencryptedElement = envelopedDoc.createElement("PrivateKey"); 148 envelopedDoc.appendChild(unencryptedElement); 149 Element node = (Element) envelopedDoc.adoptNode(rSAKeyPairDoc.getDocumentElement()); 150 unencryptedElement.appendChild(node); 151 152 Element rootElement = envelopedDoc.getDocumentElement(); 153 154 155 XMLCipher xmlCipher = 156 XMLCipher.getProviderInstance(ENCRYPTION_ALGORITHMURI,"BC"); 157 xmlCipher.init(XMLCipher.ENCRYPT_MODE, sk); 158 159 EncryptedData encryptedData = xmlCipher.getEncryptedData(); 160 encryptedData.setMimeType("text/xml"); 161 162 xmlCipher.doFinal(envelopedDoc,rootElement,true); 163 164 JAXBElement unmarshalledData = (JAXBElement) unmarshaller.unmarshal(envelopedDoc.getDocumentElement().getFirstChild()); 165 166 EncryptedDataType encryptedDataType = (EncryptedDataType) unmarshalledData.getValue(); 167 privateKeyType = xKMSObjectFactory.createPrivateKeyType(); 168 privateKeyType.setEncryptedData(encryptedDataType); 169 170 } catch (ParserConfigurationException e) { 171 log.error("Error encryption private key", e); 172 throw new XMLEncryptionException(e.getMessage(),e); 173 } catch (XMLSecurityException e) { 174 log.error("Error encryption private key", e); 175 throw new XMLEncryptionException(e.getMessage(),e); 176 } catch (JAXBException e) { 177 log.error("Error encryption private key", e); 178 throw new XMLEncryptionException(e.getMessage(),e); 179 } catch (Exception e) { 180 log.error("Error encryption private key", e); 181 throw new XMLEncryptionException(e.getMessage(),e); 182 } 183 184 return privateKeyType; 185 } 186 187 198 public static RSAPrivateKey getPrivateKeyFromEncryptedXML(PrivateKeyType privateKeyType, String sharedSecret) throws StringprepException, XMLEncryptionException{ 199 RSAPrivateKey privkey2 = null; 200 try{ 201 DocumentBuilder db = dbf.newDocumentBuilder(); 202 Document privateKeyDoc = db.newDocument(); 203 marshaller.marshal(privateKeyType, privateKeyDoc); 204 205 Element encryptedDataElement = 206 (Element) privateKeyDoc.getElementsByTagNameNS( 207 EncryptionConstants.EncryptionSpecNS, 208 EncryptionConstants._TAG_ENCRYPTEDDATA).item(0); 209 210 SecretKey sk = getSecretKeyFromPassphrase(sharedSecret,true, 24, KEY_PRIVATEKEYDATA); 211 212 XMLCipher xmlDecipher = XMLCipher.getProviderInstance(ENCRYPTION_ALGORITHMURI,"BC"); 213 214 xmlDecipher.init(XMLCipher.DECRYPT_MODE, sk); 215 216 xmlDecipher.doFinal(privateKeyDoc, encryptedDataElement); 217 218 JAXBElement<RSAKeyPairType> rSAKeyPair = (JAXBElement<RSAKeyPairType>) unmarshaller.unmarshal(privateKeyDoc.getDocumentElement().getFirstChild()); 219 220 RSAKeyPairType rSAKeyPairType = rSAKeyPair.getValue(); 221 222 223 RSAPrivateCrtKeySpec rSAPrivateKeySpec = new RSAPrivateCrtKeySpec (new BigInteger (rSAKeyPairType.getModulus()), new BigInteger (rSAKeyPairType.getExponent()), 224 new BigInteger (rSAKeyPairType.getD()), new BigInteger (rSAKeyPairType.getP()), 225 new BigInteger (rSAKeyPairType.getQ()), new BigInteger (rSAKeyPairType.getDP()), 226 new BigInteger (rSAKeyPairType.getDQ()), new BigInteger (rSAKeyPairType.getInverseQ())); 227 228 privkey2 = (RSAPrivateKey ) KeyFactory.getInstance("RSA").generatePrivate(rSAPrivateKeySpec); 229 230 } catch (InvalidKeySpecException e) { 231 log.error("Error decrypting private key", e); 232 throw new XMLEncryptionException(e.getMessage(),e); 233 } catch (NoSuchAlgorithmException e) { 234 log.error("Error decrypting private key", e); 235 throw new XMLEncryptionException(e.getMessage(),e); 236 } catch (XMLSecurityException e) { 237 log.error("Error decrypting private key", e); 238 throw new XMLEncryptionException(e.getMessage(),e); 239 } catch (JAXBException e) { 240 log.error("Error decrypting private key", e); 241 throw new XMLEncryptionException(e.getMessage(),e); 242 } catch (ParserConfigurationException e) { 243 log.error("Error decrypting private key", e); 244 throw new XMLEncryptionException(e.getMessage(),e); 245 } catch (Exception e) { 246 log.error("Error decrypting private key", e); 247 throw new XMLEncryptionException(e.getMessage(),e); 248 } 249 250 return privkey2; 251 } 252 253 268 public static SecretKey getSecretKeyFromPassphrase(String passphrase, boolean performSASLprep, int keylength, byte[] keyType) throws StringprepException, XMLEncryptionException{ 269 SecretKey retval = null; 270 try{ 271 byte[] finalKey = new byte[keylength]; 272 273 int keyIndex = 0; 274 byte[] currentKey = keyType; 275 276 277 Document doc = dbf.newDocumentBuilder().newDocument(); 278 SignatureAlgorithm sa = new SignatureAlgorithm(doc, 279 SHAREDSECRET_HASH_ALGORITH, 280 33); 281 282 String sASLPrepedPassword = passphrase; 284 if(performSASLprep){ 285 sASLPrepedPassword= Stringprep.saslprep(passphrase); 286 } 287 288 while(keyIndex < keylength){ 289 SecretKey sk = new SecretKeySpec(currentKey, 290 sa.getJCEAlgorithmString()); 291 292 Mac m = Mac.getInstance("HmacSHA1"); 293 m.init(sk); 294 m.update(sASLPrepedPassword.getBytes("ISO8859-1")); 295 byte[] mac = m.doFinal(); 296 for(int i=0;i<mac.length;i++){ 297 if(keyIndex < keylength){ 298 finalKey[keyIndex] = mac[i]; 299 keyIndex++; 300 }else{ 301 break; 302 } 303 } 304 mac[0] = (byte) (mac[0] ^ currentKey[0]); 305 currentKey = mac; 306 307 retval = new SecretKeySpec(finalKey, 308 sa.getJCEAlgorithmString()); 309 } 310 }catch(IllegalMonitorStateException e){ 311 312 } catch (ParserConfigurationException e) { 313 log.error("Error generating secret key", e); 314 throw new XMLEncryptionException(e.getMessage(),e); 315 } catch (XMLSecurityException e) { 316 log.error("Error generating secret key", e); 317 throw new XMLEncryptionException(e.getMessage(),e); 318 } catch (NoSuchAlgorithmException e) { 319 log.error("Error generating secret key", e); 320 throw new XMLEncryptionException(e.getMessage(),e); 321 } catch (InvalidKeyException e) { 322 log.error("Error generating secret key", e); 323 throw new XMLEncryptionException(e.getMessage(),e); 324 } catch (IllegalStateException e) { 325 log.error("Error generating secret key", e); 326 throw new XMLEncryptionException(e.getMessage(),e); 327 } catch (UnsupportedEncodingException e) { 328 log.error("Error generating secret key", e); 329 throw new XMLEncryptionException(e.getMessage(),e); 330 } 331 332 return retval; 333 } 334 335 346 public static Document appendKeyBindingAuthentication(Document requestDoc,String passphrase, String prototypeKeyBindingId) throws StringprepException, XMLSecurityException{ 347 SecretKey sk = XKMSUtil.getSecretKeyFromPassphrase(passphrase, true, 20, XKMSUtil.KEY_AUTHENTICATION); 348 349 org.apache.xml.security.signature.XMLSignature authXMLSig = new org.apache.xml.security.signature.XMLSignature(requestDoc, "", org.apache.xml.security.signature.XMLSignature.ALGO_ID_MAC_HMAC_SHA1, org.apache.xml.security.c14n.Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); 350 org.apache.xml.security.transforms.Transforms transforms = new org.apache.xml.security.transforms.Transforms(requestDoc); 351 transforms.addTransform(org.apache.xml.security.transforms.Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS); 352 authXMLSig.addDocument("#" + prototypeKeyBindingId, transforms, org.apache.xml.security.utils.Constants.ALGO_ID_DIGEST_SHA1); 353 354 authXMLSig.sign(sk); 355 356 Element authenticationElement = requestDoc.createElementNS("http://www.w3.org/2002/03/xkms#", "Authentication"); 357 Element keyBindingAuthenticationElement = requestDoc.createElementNS("http://www.w3.org/2002/03/xkms#", "KeyBindingAuthentication"); 358 keyBindingAuthenticationElement.appendChild(authXMLSig.getElement().cloneNode(true)); 359 authenticationElement.appendChild(keyBindingAuthenticationElement); 360 requestDoc.getDocumentElement().appendChild(authenticationElement); 361 362 return requestDoc; 363 } 364 365 public static Document appendProofOfPossession(Document requestDoc,PrivateKey privateKey, String prototypeKeyBindingId)throws XMLSecurityException{ 366 org.apache.xml.security.signature.XMLSignature xmlSig = new org.apache.xml.security.signature.XMLSignature(requestDoc, "", org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1, org.apache.xml.security.c14n.Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); 367 Transforms transforms = new org.apache.xml.security.transforms.Transforms(requestDoc); 368 transforms.addTransform(org.apache.xml.security.transforms.Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS); 369 370 xmlSig.addDocument("#" + prototypeKeyBindingId, transforms, org.apache.xml.security.utils.Constants.ALGO_ID_DIGEST_SHA1); 371 372 xmlSig.sign(privateKey); 373 374 Element pOPElement = requestDoc.createElementNS("http://www.w3.org/2002/03/xkms#", "ProofOfPossession"); 375 pOPElement.appendChild(xmlSig.getElement().cloneNode(true)); 376 requestDoc.getDocumentElement().appendChild(pOPElement); 377 378 return requestDoc; 379 } 380 381 } 382 | Popular Tags |