EC2PrivateKey.java 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. package hudson.plugins.ec2;
  2. import hudson.util.Secret;
  3. import java.io.BufferedReader;
  4. import java.io.ByteArrayInputStream;
  5. import java.io.IOException;
  6. import java.io.Reader;
  7. import java.io.StringReader;
  8. import java.security.DigestInputStream;
  9. import java.security.KeyPair;
  10. import java.security.MessageDigest;
  11. import java.security.NoSuchAlgorithmException;
  12. import java.security.PrivateKey;
  13. import java.security.Security;
  14. import org.apache.commons.codec.binary.Hex;
  15. import org.bouncycastle.openssl.PEMReader;
  16. import org.bouncycastle.openssl.PasswordFinder;
  17. import com.amazonaws.AmazonClientException;
  18. import com.amazonaws.services.ec2.AmazonEC2;
  19. import com.amazonaws.services.ec2.model.KeyPairInfo;
  20. /**
  21. * RSA private key (the one that you generate with ec2-add-keypair.) Starts with
  22. * "----- BEGIN RSA PRIVATE KEY------\n".
  23. *
  24. * @author Kohsuke Kawaguchi
  25. */
  26. public final class EC2PrivateKey {
  27. private final Secret privateKey;
  28. public EC2PrivateKey(final String privateKey) {
  29. this.privateKey = Secret.fromString(privateKey.trim());
  30. }
  31. /**
  32. * Obtains the fingerprint of the key in the "ab:cd:ef:...:12" format.
  33. */
  34. /**
  35. * Obtains the fingerprint of the key in the "ab:cd:ef:...:12" format.
  36. */
  37. public String getFingerprint() throws IOException {
  38. Security
  39. .addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
  40. Reader r =
  41. new BufferedReader(new StringReader(privateKey.toString()));
  42. PEMReader pem = new PEMReader(r, new PasswordFinder() {
  43. public char[] getPassword() {
  44. throw PRIVATE_KEY_WITH_PASSWORD;
  45. }
  46. });
  47. try {
  48. KeyPair pair = (KeyPair) pem.readObject();
  49. if (pair == null) {
  50. return null;
  51. }
  52. PrivateKey key = pair.getPrivate();
  53. return digest(key);
  54. } catch (RuntimeException e) {
  55. if (e == PRIVATE_KEY_WITH_PASSWORD) {
  56. throw new IOException(
  57. "This private key is password protected, which isn't supported yet");
  58. }
  59. throw e;
  60. }
  61. }
  62. /**
  63. * Is this file really a private key?
  64. */
  65. public boolean isPrivateKey() throws IOException {
  66. BufferedReader br =
  67. new BufferedReader(new StringReader(privateKey.toString()));
  68. String line;
  69. while ((line = br.readLine()) != null) {
  70. if (line.equals("-----BEGIN RSA PRIVATE KEY-----")) {
  71. return true;
  72. }
  73. }
  74. return false;
  75. }
  76. /**
  77. * Finds the {@link KeyPairInfo} that corresponds to this key in EC2.
  78. */
  79. public com.amazonaws.services.ec2.model.KeyPair find(
  80. final AmazonEC2 ec2) throws IOException, AmazonClientException {
  81. String fp = getFingerprint();
  82. for (KeyPairInfo kp : ec2.describeKeyPairs().getKeyPairs()) {
  83. if (kp.getKeyFingerprint().equalsIgnoreCase(fp)) {
  84. com.amazonaws.services.ec2.model.KeyPair keyPair =
  85. new com.amazonaws.services.ec2.model.KeyPair();
  86. keyPair.setKeyName(kp.getKeyName());
  87. keyPair.setKeyFingerprint(fp);
  88. keyPair.setKeyMaterial(Secret.toString(privateKey));
  89. return keyPair;
  90. }
  91. }
  92. return null;
  93. }
  94. @Override
  95. public int hashCode() {
  96. return privateKey.hashCode();
  97. }
  98. @Override
  99. public boolean equals(final Object that) {
  100. return that instanceof EC2PrivateKey
  101. && privateKey.equals(((EC2PrivateKey) that).privateKey);
  102. }
  103. @Override
  104. public String toString() {
  105. return privateKey.toString();
  106. }
  107. /* package */static String digest(final PrivateKey k)
  108. throws IOException {
  109. try {
  110. MessageDigest md5 = MessageDigest.getInstance("SHA1");
  111. DigestInputStream in =
  112. new DigestInputStream(new ByteArrayInputStream(
  113. k.getEncoded()), md5);
  114. try {
  115. while (in.read(new byte[128]) > 0) {
  116. ; // simply discard the input
  117. }
  118. } finally {
  119. in.close();
  120. }
  121. StringBuilder buf = new StringBuilder();
  122. char[] hex = Hex.encodeHex(md5.digest());
  123. for (int i = 0; i < hex.length; i += 2) {
  124. if (buf.length() > 0) {
  125. buf.append(':');
  126. }
  127. buf.append(hex, i, 2);
  128. }
  129. return buf.toString();
  130. } catch (NoSuchAlgorithmException e) {
  131. throw new AssertionError(e);
  132. }
  133. }
  134. private static final RuntimeException PRIVATE_KEY_WITH_PASSWORD =
  135. new RuntimeException();
  136. }