forked from aws/aws-sdk-java
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPEM.java
More file actions
151 lines (145 loc) · 5.43 KB
/
PEM.java
File metadata and controls
151 lines (145 loc) · 5.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
* Copyright 2013-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazonaws.auth;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.List;
import com.amazonaws.util.Base64;
/**
* A PEM utility that can be used to read keys from PEM. With this PEM utility,
* private keys in either PKCS#1 or PKCS#8 PEM encoded format can be read
* without the need to depend on the Bouncy Castle library.
* <p>
* Some background information:
* <ul>
* <li>Interestingly, the creation of a CloudFront Key Pair via the AWS console
* would result in a private key in PKCS#1 PEM format.</li>
* <li>Unfortunately, the JDK doesn't provide a means to load PEM key encoded in
* PKCS#1 without adding the Bouncy Castle to the classpath. The JDK can only
* load PEM key encoded in PKCS#8 encoding.</li>
* <li>One the other hand, one can use openssl to convert a PEM file from PKCS#1
* to PKCS#8. Example:
*
* <pre>
* openssl pkcs8 -topk8 -in pk-APKAJM22QV32R3I2XVIQ.pem -inform pem -out pk-APKAJM22QV32R3I2XVIQ_pk8.pem -outform pem -nocrypt
* </pre>
*
* </li>
* </ul>
*/
public enum PEM {
;
private static final String BEGIN_MARKER = "-----BEGIN ";
/**
* Returns the first private key that is found from the input stream of a
* PEM file.
*
* @throws InvalidKeySpecException
* if failed to convert the DER bytes into a private key.
* @throws IllegalArgumentException
* if no private key is found.
*/
public static PrivateKey readPrivateKey(InputStream is)
throws InvalidKeySpecException, IOException {
List<PEMObject> objects = readPEMObjects(is);
for (PEMObject object : objects) {
switch (object.getPEMObjectType()) {
case PRIVATE_KEY_PKCS1:
return RSA.privateKeyFromPKCS1(object.getDerBytes());
case PRIVATE_KEY_PKCS8:
return RSA.privateKeyFromPKCS8(object.getDerBytes());
default:
break;
}
}
throw new IllegalArgumentException("Found no private key");
}
/**
* Returns the first public key that is found from the input stream of a PEM
* file.
*
* @throws InvalidKeySpecException
* if failed to convert the DER bytes into a public key.
* @throws IllegalArgumentException
* if no public key is found.
*/
public static PublicKey readPublicKey(InputStream is)
throws InvalidKeySpecException, IOException {
List<PEMObject> objects = readPEMObjects(is);
for (PEMObject object : objects) {
switch (object.getPEMObjectType()) {
case PUBLIC_KEY_X509:
return RSA.publicKeyFrom(object.getDerBytes());
default:
break;
}
}
throw new IllegalArgumentException("Found no public key");
}
/**
* A lower level API used to returns all PEM objects that can be read off
* from the input stream of a PEM file.
* <p>
* This method can be useful if more than one PEM object of different types
* are embedded in the same PEM file.
*/
public static List<PEMObject> readPEMObjects(InputStream is)
throws IOException {
List<PEMObject> pemContents = new ArrayList<PEMObject>();
/*
* State of reading: set to true if reading content between a
* begin-marker and end-marker; false otherwise.
*/
boolean readingContent = false;
String beginMarker = null;
String endMarker = null;
StringBuffer sb = null;
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
try {
while ((line = reader.readLine()) != null) {
if (readingContent) {
if (line.indexOf(endMarker) != -1) {
pemContents.add( // completed reading one PEM object
new PEMObject(beginMarker, Base64.decode(sb
.toString())));
readingContent = false;
} else {
sb.append(line.trim());
}
} else {
if (line.indexOf(BEGIN_MARKER) != -1) {
readingContent = true;
beginMarker = line.trim();
endMarker = beginMarker.replace("BEGIN", "END");
sb = new StringBuffer();
}
}
}
return pemContents;
} finally {
try {
reader.close();
} catch (IOException ignore) {
}
}
}
}