1 /* |
1 /* |
2 * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. |
2 * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Sun designates this |
7 * published by the Free Software Foundation. Sun designates this |
154 private static class AliasInfo { |
154 private static class AliasInfo { |
155 |
155 |
156 // CKA_CLASS - entry type |
156 // CKA_CLASS - entry type |
157 private CK_ATTRIBUTE type = null; |
157 private CK_ATTRIBUTE type = null; |
158 |
158 |
159 // CKA_LABEL of cert |
159 // CKA_LABEL of cert and secret key |
160 private String label = null; |
160 private String label = null; |
161 |
161 |
162 // CKA_ID - of private key/cert |
162 // CKA_ID of the private key/cert pair |
163 private byte[] id = null; |
163 private byte[] id = null; |
164 |
164 |
165 // CKA_TRUSTED - true if cert is trusted |
165 // CKA_TRUSTED - true if cert is trusted |
166 private boolean trusted = false; |
166 private boolean trusted = false; |
167 |
167 |
869 |
869 |
870 private void login(CallbackHandler handler) throws LoginException { |
870 private void login(CallbackHandler handler) throws LoginException { |
871 if ((token.tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) == 0) { |
871 if ((token.tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) == 0) { |
872 token.provider.login(null, handler); |
872 token.provider.login(null, handler); |
873 } else { |
873 } else { |
874 |
|
875 // token supports protected authentication path |
874 // token supports protected authentication path |
876 // (external pin-pad, for example) |
875 // (external pin-pad, for example) |
877 |
|
878 if (handler != null && |
876 if (handler != null && |
879 !token.config.getKeyStoreCompatibilityMode()) { |
877 !token.config.getKeyStoreCompatibilityMode()) { |
880 throw new LoginException("can not specify password if token " + |
878 throw new LoginException("can not specify password if token " + |
881 "supports protected authentication path"); |
879 "supports protected authentication path"); |
882 } |
880 } |
1128 |
1126 |
1129 KeyStore.SecretKeyEntry ske = (KeyStore.SecretKeyEntry)entry; |
1127 KeyStore.SecretKeyEntry ske = (KeyStore.SecretKeyEntry)entry; |
1130 SecretKey skey = ske.getSecretKey(); |
1128 SecretKey skey = ske.getSecretKey(); |
1131 |
1129 |
1132 try { |
1130 try { |
1133 // first see if the key already exists. |
1131 // first check if the key already exists |
1134 // if so, update the CKA_LABEL |
1132 AliasInfo aliasInfo = aliasMap.get(alias); |
1135 if (!updateSkey(alias)) { |
1133 |
1136 |
1134 if (aliasInfo != null) { |
1137 // key entry does not exist. |
|
1138 // delete existing entry for alias and |
|
1139 // create new secret key entry |
|
1140 // (new entry might be a secret key |
|
1141 // session object converted into a token object) |
|
1142 |
|
1143 engineDeleteEntry(alias); |
1135 engineDeleteEntry(alias); |
1144 storeSkey(alias, ske); |
|
1145 } |
1136 } |
|
1137 storeSkey(alias, ske); |
|
1138 |
1146 } catch (PKCS11Exception pe) { |
1139 } catch (PKCS11Exception pe) { |
1147 throw new KeyStoreException(pe); |
1140 throw new KeyStoreException(pe); |
1148 } |
1141 } |
1149 |
1142 |
1150 } else { |
1143 } else { |
1394 } |
1387 } |
1395 throw new KeyStoreException("unknown key type"); |
1388 throw new KeyStoreException("unknown key type"); |
1396 } |
1389 } |
1397 } |
1390 } |
1398 |
1391 |
1399 /** |
|
1400 * return true if update occurred |
|
1401 */ |
|
1402 private boolean updateSkey(String alias) |
|
1403 throws KeyStoreException, PKCS11Exception { |
|
1404 |
|
1405 Session session = null; |
|
1406 try { |
|
1407 session = token.getOpSession(); |
|
1408 |
|
1409 // first update existing secret key CKA_LABEL |
|
1410 |
|
1411 THandle h = getTokenObject(session, ATTR_CLASS_SKEY, null, alias); |
|
1412 if (h.type != ATTR_CLASS_SKEY) { |
|
1413 if (debug != null) { |
|
1414 debug.println("did not find secret key " + |
|
1415 "with CKA_LABEL [" + alias + "]"); |
|
1416 } |
|
1417 return false; |
|
1418 } |
|
1419 CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { |
|
1420 new CK_ATTRIBUTE(CKA_LABEL, alias) }; |
|
1421 token.p11.C_SetAttributeValue(session.id(), h.handle, attrs); |
|
1422 |
|
1423 if (debug != null) { |
|
1424 debug.println("updateSkey set new alias [" + |
|
1425 alias + |
|
1426 "] for secret key entry"); |
|
1427 } |
|
1428 |
|
1429 return true; |
|
1430 } finally { |
|
1431 token.releaseSession(session); |
|
1432 } |
|
1433 } |
|
1434 |
1392 |
1435 /** |
1393 /** |
1436 * XXX On ibutton, when you C_SetAttribute(CKA_ID) for a private key |
1394 * XXX On ibutton, when you C_SetAttribute(CKA_ID) for a private key |
1437 * it not only changes the CKA_ID of the private key, |
1395 * it not only changes the CKA_ID of the private key, |
1438 * it changes the CKA_ID of the corresponding cert too. |
1396 * it changes the CKA_ID of the corresponding cert too. |
1530 } finally { |
1488 } finally { |
1531 token.releaseSession(session); |
1489 token.releaseSession(session); |
1532 } |
1490 } |
1533 } |
1491 } |
1534 |
1492 |
1535 private void updateP11Skey(String alias, P11Key key) |
|
1536 throws PKCS11Exception { |
|
1537 |
|
1538 Session session = null; |
|
1539 try { |
|
1540 session = token.getOpSession(); |
|
1541 |
|
1542 // session key - convert to token key and set CKA_LABEL |
|
1543 |
|
1544 CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { |
|
1545 ATTR_TOKEN_TRUE, |
|
1546 new CK_ATTRIBUTE(CKA_LABEL, alias) }; |
|
1547 token.p11.C_CopyObject(session.id(), key.keyID, attrs); |
|
1548 if (debug != null) { |
|
1549 debug.println("updateP11Skey copied secret session key " + |
|
1550 "for [" + |
|
1551 alias + |
|
1552 "] to token entry"); |
|
1553 } |
|
1554 } finally { |
|
1555 token.releaseSession(session); |
|
1556 } |
|
1557 } |
|
1558 |
|
1559 private void updateP11Pkey(String alias, CK_ATTRIBUTE attribute, P11Key key) |
1493 private void updateP11Pkey(String alias, CK_ATTRIBUTE attribute, P11Key key) |
1560 throws PKCS11Exception { |
1494 throws PKCS11Exception { |
1561 |
1495 |
1562 // if token key, update alias. |
1496 // if token key, update alias. |
1563 // if session key, convert to token key. |
1497 // if session key, convert to token key. |
1687 |
1621 |
1688 private void storeSkey(String alias, KeyStore.SecretKeyEntry ske) |
1622 private void storeSkey(String alias, KeyStore.SecretKeyEntry ske) |
1689 throws PKCS11Exception, KeyStoreException { |
1623 throws PKCS11Exception, KeyStoreException { |
1690 |
1624 |
1691 SecretKey skey = ske.getSecretKey(); |
1625 SecretKey skey = ske.getSecretKey(); |
1692 long keyType = CKK_GENERIC_SECRET; |
1626 // No need to specify CKA_CLASS, CKA_KEY_TYPE, CKA_VALUE since |
1693 |
1627 // they are handled in P11SecretKeyFactory.createKey() method. |
1694 if (skey instanceof P11Key && this.token == ((P11Key)skey).token) { |
|
1695 updateP11Skey(alias, (P11Key)skey); |
|
1696 return; |
|
1697 } |
|
1698 |
|
1699 if ("AES".equalsIgnoreCase(skey.getAlgorithm())) { |
|
1700 keyType = CKK_AES; |
|
1701 } else if ("Blowfish".equalsIgnoreCase(skey.getAlgorithm())) { |
|
1702 keyType = CKK_BLOWFISH; |
|
1703 } else if ("DES".equalsIgnoreCase(skey.getAlgorithm())) { |
|
1704 keyType = CKK_DES; |
|
1705 } else if ("DESede".equalsIgnoreCase(skey.getAlgorithm())) { |
|
1706 keyType = CKK_DES3; |
|
1707 } else if ("RC4".equalsIgnoreCase(skey.getAlgorithm()) || |
|
1708 "ARCFOUR".equalsIgnoreCase(skey.getAlgorithm())) { |
|
1709 keyType = CKK_RC4; |
|
1710 } |
|
1711 |
|
1712 CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { |
1628 CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { |
1713 ATTR_SKEY_TOKEN_TRUE, |
1629 ATTR_SKEY_TOKEN_TRUE, |
1714 ATTR_CLASS_SKEY, |
1630 ATTR_PRIVATE_TRUE, |
1715 ATTR_PRIVATE_TRUE, |
1631 new CK_ATTRIBUTE(CKA_LABEL, alias), |
1716 new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType), |
1632 }; |
1717 new CK_ATTRIBUTE(CKA_LABEL, alias), |
|
1718 new CK_ATTRIBUTE(CKA_VALUE, skey.getEncoded()) }; |
|
1719 attrs = token.getAttributes |
|
1720 (TemplateManager.O_IMPORT, CKO_SECRET_KEY, keyType, attrs); |
|
1721 |
|
1722 // create the new entry |
|
1723 Session session = null; |
|
1724 try { |
1633 try { |
1725 session = token.getOpSession(); |
1634 P11SecretKeyFactory.convertKey(token, skey, null, attrs); |
1726 token.p11.C_CreateObject(session.id(), attrs); |
1635 } catch (InvalidKeyException ike) { |
1727 if (debug != null) { |
1636 // re-throw KeyStoreException to match javadoc |
1728 debug.println("storeSkey created token secret key for [" + |
1637 throw new KeyStoreException("Cannot convert to PKCS11 keys", ike); |
1729 alias + |
1638 } |
1730 "]"); |
1639 |
1731 } |
1640 // update global alias map |
1732 } finally { |
1641 aliasMap.put(alias, new AliasInfo(alias)); |
1733 token.releaseSession(session); |
1642 |
|
1643 if (debug != null) { |
|
1644 debug.println("storeSkey created token secret key for [" + |
|
1645 alias + "]"); |
1734 } |
1646 } |
1735 } |
1647 } |
1736 |
1648 |
1737 private static CK_ATTRIBUTE[] addAttribute(CK_ATTRIBUTE[] attrs, CK_ATTRIBUTE attr) { |
1649 private static CK_ATTRIBUTE[] addAttribute(CK_ATTRIBUTE[] attrs, CK_ATTRIBUTE attr) { |
1738 int n = attrs.length; |
1650 int n = attrs.length; |
2490 |
2402 |
2491 // create list secret key CKA_LABELS - |
2403 // create list secret key CKA_LABELS - |
2492 // if there are duplicates (either between secret keys, |
2404 // if there are duplicates (either between secret keys, |
2493 // or between a secret key and another object), |
2405 // or between a secret key and another object), |
2494 // throw an exception |
2406 // throw an exception |
2495 HashSet<String> sKeySet = new HashSet<String>(); |
2407 HashMap<String, AliasInfo> sKeyMap = |
|
2408 new HashMap<String, AliasInfo>(); |
2496 |
2409 |
2497 attrs = new CK_ATTRIBUTE[] { |
2410 attrs = new CK_ATTRIBUTE[] { |
2498 ATTR_SKEY_TOKEN_TRUE, |
2411 ATTR_SKEY_TOKEN_TRUE, |
2499 ATTR_CLASS_SKEY, |
2412 ATTR_CLASS_SKEY, |
2500 }; |
2413 }; |
2505 token.p11.C_GetAttributeValue(session.id(), handle, attrs); |
2418 token.p11.C_GetAttributeValue(session.id(), handle, attrs); |
2506 if (attrs[0].pValue != null) { |
2419 if (attrs[0].pValue != null) { |
2507 |
2420 |
2508 // there is a CKA_LABEL |
2421 // there is a CKA_LABEL |
2509 String cka_label = new String(attrs[0].getCharArray()); |
2422 String cka_label = new String(attrs[0].getCharArray()); |
2510 if (!sKeySet.contains(cka_label)) { |
2423 if (sKeyMap.get(cka_label) == null) { |
2511 sKeySet.add(cka_label); |
2424 sKeyMap.put(cka_label, new AliasInfo(cka_label)); |
2512 } else { |
2425 } else { |
2513 throw new KeyStoreException("invalid KeyStore state: " + |
2426 throw new KeyStoreException("invalid KeyStore state: " + |
2514 "found multiple secret keys sharing same " + |
2427 "found multiple secret keys sharing same " + |
2515 "CKA_LABEL [" + |
2428 "CKA_LABEL [" + |
2516 cka_label + |
2429 cka_label + |
2521 |
2434 |
2522 // update global aliasMap with alias mappings |
2435 // update global aliasMap with alias mappings |
2523 ArrayList<AliasInfo> matchedCerts = |
2436 ArrayList<AliasInfo> matchedCerts = |
2524 mapPrivateKeys(pkeyIDs, certMap); |
2437 mapPrivateKeys(pkeyIDs, certMap); |
2525 boolean sharedLabel = mapCerts(matchedCerts, certMap); |
2438 boolean sharedLabel = mapCerts(matchedCerts, certMap); |
2526 mapSecretKeys(sKeySet); |
2439 mapSecretKeys(sKeyMap); |
2527 |
2440 |
2528 return sharedLabel; |
2441 return sharedLabel; |
2529 |
2442 |
2530 } finally { |
2443 } finally { |
2531 token.releaseSession(session); |
2444 token.releaseSession(session); |
2545 */ |
2458 */ |
2546 private ArrayList<AliasInfo> mapPrivateKeys(ArrayList<byte[]> pkeyIDs, |
2459 private ArrayList<AliasInfo> mapPrivateKeys(ArrayList<byte[]> pkeyIDs, |
2547 HashMap<String, HashSet<AliasInfo>> certMap) |
2460 HashMap<String, HashSet<AliasInfo>> certMap) |
2548 throws PKCS11Exception, CertificateException { |
2461 throws PKCS11Exception, CertificateException { |
2549 |
2462 |
2550 // global alias map |
2463 // reset global alias map |
2551 aliasMap = new HashMap<String, AliasInfo>(); |
2464 aliasMap = new HashMap<String, AliasInfo>(); |
2552 |
2465 |
2553 // list of matched certs that we will return |
2466 // list of matched certs that we will return |
2554 ArrayList<AliasInfo> matchedCerts = new ArrayList<AliasInfo>(); |
2467 ArrayList<AliasInfo> matchedCerts = new ArrayList<AliasInfo>(); |
2555 |
2468 |
2720 |
2633 |
2721 /** |
2634 /** |
2722 * If the secret key shares a CKA_LABEL with another entry, |
2635 * If the secret key shares a CKA_LABEL with another entry, |
2723 * throw an exception |
2636 * throw an exception |
2724 */ |
2637 */ |
2725 private void mapSecretKeys(HashSet<String> sKeySet) |
2638 private void mapSecretKeys(HashMap<String, AliasInfo> sKeyMap) |
2726 throws KeyStoreException { |
2639 throws KeyStoreException { |
2727 for (String label : sKeySet) { |
2640 for (String label : sKeyMap.keySet()) { |
2728 if (!aliasMap.containsKey(label)) { |
2641 if (aliasMap.containsKey(label)) { |
2729 aliasMap.put(label, new AliasInfo(label)); |
|
2730 } else { |
|
2731 throw new KeyStoreException("invalid KeyStore state: " + |
2642 throw new KeyStoreException("invalid KeyStore state: " + |
2732 "found secret key sharing CKA_LABEL [" + |
2643 "found secret key sharing CKA_LABEL [" + |
2733 label + |
2644 label + |
2734 "] with another token object"); |
2645 "] with another token object"); |
2735 } |
2646 } |
2736 } |
2647 } |
|
2648 aliasMap.putAll(sKeyMap); |
2737 } |
2649 } |
2738 |
2650 |
2739 private void dumpTokenMap() { |
2651 private void dumpTokenMap() { |
2740 Set<String> aliases = aliasMap.keySet(); |
2652 Set<String> aliases = aliasMap.keySet(); |
2741 System.out.println("Token Alias Map:"); |
2653 System.out.println("Token Alias Map:"); |