Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
a77b812a
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
4
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
a77b812a
编写于
1月 23, 2013
作者:
V
vinnie
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
8005408: KeyStore API enhancements
Reviewed-by: mullan
上级
b691337a
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
1502 addition
and
167 deletion
+1502
-167
src/share/classes/java/security/KeyStore.java
src/share/classes/java/security/KeyStore.java
+169
-2
src/share/classes/java/security/PKCS12Attribute.java
src/share/classes/java/security/PKCS12Attribute.java
+285
-0
src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java
src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java
+710
-164
src/share/classes/sun/security/x509/AlgorithmId.java
src/share/classes/sun/security/x509/AlgorithmId.java
+14
-1
test/sun/security/pkcs12/StorePasswordTest.java
test/sun/security/pkcs12/StorePasswordTest.java
+92
-0
test/sun/security/pkcs12/StoreSecretKeyTest.java
test/sun/security/pkcs12/StoreSecretKeyTest.java
+86
-0
test/sun/security/pkcs12/StoreTrustedCertTest.java
test/sun/security/pkcs12/StoreTrustedCertTest.java
+117
-0
test/sun/security/pkcs12/trusted.pem
test/sun/security/pkcs12/trusted.pem
+29
-0
未找到文件。
src/share/classes/java/security/KeyStore.java
浏览文件 @
a77b812a
...
...
@@ -26,6 +26,7 @@
package
java.security
;
import
java.io.*
;
import
java.net.URI
;
import
java.security.cert.Certificate
;
import
java.security.cert.X509Certificate
;
import
java.security.cert.CertificateException
;
...
...
@@ -405,7 +406,44 @@ public class KeyStore {
*
* @since 1.5
*/
public
static
interface
Entry
{
}
public
static
interface
Entry
{
/**
* Retrieves the attributes associated with an entry.
* <p>
* The default implementation returns an empty {@code Set}.
*
* @return an unmodifiable {@code Set} of attributes, possibly empty
*
* @since 1.8
*/
public
default
Set
<
Attribute
>
getAttributes
()
{
return
Collections
.<
Attribute
>
emptySet
();
}
/**
* An attribute associated with a keystore entry.
* It comprises a name and one or more values.
*
* @since 1.8
*/
public
interface
Attribute
{
/**
* Returns the attribute's name.
*
* @return the attribute name
*/
public
String
getName
();
/**
* Returns the attribute's value.
* Multi-valued attributes encode their values as a single string.
*
* @return the attribute value
*/
public
String
getValue
();
}
}
/**
* A <code>KeyStore</code> entry that holds a <code>PrivateKey</code>
...
...
@@ -417,6 +455,7 @@ public class KeyStore {
private
final
PrivateKey
privKey
;
private
final
Certificate
[]
chain
;
private
final
Set
<
Attribute
>
attributes
;
/**
* Constructs a <code>PrivateKeyEntry</code> with a
...
...
@@ -443,7 +482,39 @@ public class KeyStore {
* in the end entity <code>Certificate</code> (at index 0)
*/
public
PrivateKeyEntry
(
PrivateKey
privateKey
,
Certificate
[]
chain
)
{
if
(
privateKey
==
null
||
chain
==
null
)
{
this
(
privateKey
,
chain
,
Collections
.<
Attribute
>
emptySet
());
}
/**
* Constructs a {@code PrivateKeyEntry} with a {@code PrivateKey} and
* corresponding certificate chain and associated entry attributes.
*
* <p> The specified {@code chain} and {@code attributes} are cloned
* before they are stored in the new {@code PrivateKeyEntry} object.
*
* @param privateKey the {@code PrivateKey}
* @param chain an array of {@code Certificate}s
* representing the certificate chain.
* The chain must be ordered and contain a
* {@code Certificate} at index 0
* corresponding to the private key.
* @param attributes the attributes
*
* @exception NullPointerException if {@code privateKey}, {@code chain}
* or {@code attributes} is {@code null}
* @exception IllegalArgumentException if the specified chain has a
* length of 0, if the specified chain does not contain
* {@code Certificate}s of the same type,
* or if the {@code PrivateKey} algorithm
* does not match the algorithm of the {@code PublicKey}
* in the end entity {@code Certificate} (at index 0)
*
* @since 1.8
*/
public
PrivateKeyEntry
(
PrivateKey
privateKey
,
Certificate
[]
chain
,
Set
<
Attribute
>
attributes
)
{
if
(
privateKey
==
null
||
chain
==
null
||
attributes
==
null
)
{
throw
new
NullPointerException
(
"invalid null input"
);
}
if
(
chain
.
length
==
0
)
{
...
...
@@ -478,6 +549,9 @@ public class KeyStore {
}
else
{
this
.
chain
=
clonedChain
;
}
this
.
attributes
=
Collections
.
unmodifiableSet
(
new
HashSet
<>(
attributes
));
}
/**
...
...
@@ -518,6 +592,19 @@ public class KeyStore {
return
chain
[
0
];
}
/**
* Retrieves the attributes associated with an entry.
* <p>
*
* @return an unmodifiable {@code Set} of attributes, possibly empty
*
* @since 1.8
*/
@Override
public
Set
<
Attribute
>
getAttributes
()
{
return
attributes
;
}
/**
* Returns a string representation of this PrivateKeyEntry.
* @return a string representation of this PrivateKeyEntry.
...
...
@@ -543,6 +630,7 @@ public class KeyStore {
public
static
final
class
SecretKeyEntry
implements
Entry
{
private
final
SecretKey
sKey
;
private
final
Set
<
Attribute
>
attributes
;
/**
* Constructs a <code>SecretKeyEntry</code> with a
...
...
@@ -558,6 +646,32 @@ public class KeyStore {
throw
new
NullPointerException
(
"invalid null input"
);
}
this
.
sKey
=
secretKey
;
this
.
attributes
=
Collections
.<
Attribute
>
emptySet
();
}
/**
* Constructs a {@code SecretKeyEntry} with a {@code SecretKey} and
* associated entry attributes.
*
* <p> The specified {@code attributes} is cloned before it is stored
* in the new {@code SecretKeyEntry} object.
*
* @param secretKey the {@code SecretKey}
* @param attributes the attributes
*
* @exception NullPointerException if {@code secretKey} or
* {@code attributes} is {@code null}
*
* @since 1.8
*/
public
SecretKeyEntry
(
SecretKey
secretKey
,
Set
<
Attribute
>
attributes
)
{
if
(
secretKey
==
null
||
attributes
==
null
)
{
throw
new
NullPointerException
(
"invalid null input"
);
}
this
.
sKey
=
secretKey
;
this
.
attributes
=
Collections
.
unmodifiableSet
(
new
HashSet
<>(
attributes
));
}
/**
...
...
@@ -569,6 +683,19 @@ public class KeyStore {
return
sKey
;
}
/**
* Retrieves the attributes associated with an entry.
* <p>
*
* @return an unmodifiable {@code Set} of attributes, possibly empty
*
* @since 1.8
*/
@Override
public
Set
<
Attribute
>
getAttributes
()
{
return
attributes
;
}
/**
* Returns a string representation of this SecretKeyEntry.
* @return a string representation of this SecretKeyEntry.
...
...
@@ -587,6 +714,7 @@ public class KeyStore {
public
static
final
class
TrustedCertificateEntry
implements
Entry
{
private
final
Certificate
cert
;
private
final
Set
<
Attribute
>
attributes
;
/**
* Constructs a <code>TrustedCertificateEntry</code> with a
...
...
@@ -602,6 +730,32 @@ public class KeyStore {
throw
new
NullPointerException
(
"invalid null input"
);
}
this
.
cert
=
trustedCert
;
this
.
attributes
=
Collections
.<
Attribute
>
emptySet
();
}
/**
* Constructs a {@code TrustedCertificateEntry} with a
* trusted {@code Certificate} and associated entry attributes.
*
* <p> The specified {@code attributes} is cloned before it is stored
* in the new {@code TrustedCertificateEntry} object.
*
* @param trustedCert the trusted {@code Certificate}
* @param attributes the attributes
*
* @exception NullPointerException if {@code trustedCert} or
* {@code attributes} is {@code null}
*
* @since 1.8
*/
public
TrustedCertificateEntry
(
Certificate
trustedCert
,
Set
<
Attribute
>
attributes
)
{
if
(
trustedCert
==
null
||
attributes
==
null
)
{
throw
new
NullPointerException
(
"invalid null input"
);
}
this
.
cert
=
trustedCert
;
this
.
attributes
=
Collections
.
unmodifiableSet
(
new
HashSet
<>(
attributes
));
}
/**
...
...
@@ -613,6 +767,19 @@ public class KeyStore {
return
cert
;
}
/**
* Retrieves the attributes associated with an entry.
* <p>
*
* @return an unmodifiable {@code Set} of attributes, possibly empty
*
* @since 1.8
*/
@Override
public
Set
<
Attribute
>
getAttributes
()
{
return
attributes
;
}
/**
* Returns a string representation of this TrustedCertificateEntry.
* @return a string representation of this TrustedCertificateEntry.
...
...
src/share/classes/java/security/PKCS12Attribute.java
0 → 100644
浏览文件 @
a77b812a
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package
java.security
;
import
java.io.IOException
;
import
java.math.BigInteger
;
import
java.util.Arrays
;
import
java.util.regex.Pattern
;
import
sun.security.util.*
;
/**
* An attribute associated with a PKCS12 keystore entry.
* The attribute name is an ASN.1 Object Identifier and the attribute
* value is a set of ASN.1 types.
*
* @since 1.8
*/
public
final
class
PKCS12Attribute
implements
KeyStore
.
Entry
.
Attribute
{
private
static
final
Pattern
COLON_SEPARATED_HEX_PAIRS
=
Pattern
.
compile
(
"^[0-9a-fA-F]{2}(:[0-9a-fA-F]{2})+$"
);
private
String
name
;
private
String
value
;
private
byte
[]
encoded
;
private
int
hashValue
=
-
1
;
/**
* Constructs a PKCS12 attribute from its name and value.
* The name is an ASN.1 Object Identifier represented as a list of
* dot-separated integers.
* A string value is represented as the string itself.
* A binary value is represented as a string of colon-separated
* pairs of hexadecimal digits.
* Multi-valued attributes are represented as a comma-separated
* list of values, enclosed in square brackets. See
* {@link Arrays.toString}.
* <p>
* A string value will be DER-encoded as an ASN.1 UTF8String and a
* binary value will be DER-encoded as an ASN.1 Octet String.
*
* @param name the attribute's identifier
* @param value the attribute's value
*
* @exception NullPointerException if {@code name} or {@code value}
* is {@code null}
* @exception IllegalArgumentException if {@code name} or
* {@code value} is incorrectly formatted
*/
public
PKCS12Attribute
(
String
name
,
String
value
)
{
if
(
name
==
null
||
value
==
null
)
{
throw
new
NullPointerException
();
}
// Validate name
ObjectIdentifier
type
;
try
{
type
=
new
ObjectIdentifier
(
name
);
}
catch
(
IOException
e
)
{
throw
new
IllegalArgumentException
(
"Incorrect format: name"
,
e
);
}
this
.
name
=
name
;
// Validate value
int
length
=
value
.
length
();
String
[]
values
;
if
(
value
.
charAt
(
0
)
==
'['
&&
value
.
charAt
(
length
-
1
)
==
']'
)
{
values
=
value
.
substring
(
1
,
length
-
1
).
split
(
", "
);
}
else
{
values
=
new
String
[]{
value
};
}
this
.
value
=
value
;
try
{
this
.
encoded
=
encode
(
type
,
values
);
}
catch
(
IOException
e
)
{
throw
new
IllegalArgumentException
(
"Incorrect format: value"
,
e
);
}
}
/**
* Constructs a PKCS12 attribute from its ASN.1 DER encoding.
* The DER encoding is specified by the following ASN.1 definition:
* <pre>
*
* Attribute ::= SEQUENCE {
* type AttributeType,
* values SET OF AttributeValue
* }
* AttributeType ::= OBJECT IDENTIFIER
* AttributeValue ::= ANY defined by type
*
* </pre>
*
* @param encoded the attribute's ASN.1 DER encoding. It is cloned
* to prevent subsequent modificaion.
*
* @exception NullPointerException if {@code encoded} is
* {@code null}
* @exception IllegalArgumentException if {@code encoded} is
* incorrectly formatted
*/
public
PKCS12Attribute
(
byte
[]
encoded
)
{
if
(
encoded
==
null
)
{
throw
new
NullPointerException
();
}
this
.
encoded
=
encoded
.
clone
();
try
{
parse
(
encoded
);
}
catch
(
IOException
e
)
{
throw
new
IllegalArgumentException
(
"Incorrect format: encoded"
,
e
);
}
}
/**
* Returns the attribute's ASN.1 Object Identifier represented as a
* list of dot-separated integers.
*
* @return the attribute's identifier
*/
@Override
public
String
getName
()
{
return
name
;
}
/**
* Returns the attribute's ASN.1 DER-encoded value as a string.
* An ASN.1 DER-encoded value is returned in one of the following
* {@code String} formats:
* <ul>
* <li> the DER encoding of a basic ASN.1 type that has a natural
* string representation is returned as the string itself.
* Such types are currently limited to BOOLEAN, INTEGER,
* OBJECT IDENTIFIER, UTCTime, GeneralizedTime and the
* following six ASN.1 string types: UTF8String,
* PrintableString, T61String, IA5String, BMPString and
* GeneralString.
* <li> the DER encoding of any other ASN.1 type is not decoded but
* returned as a binary string of colon-separated pairs of
* hexadecimal digits.
* </ul>
* Multi-valued attributes are represented as a comma-separated
* list of values, enclosed in square brackets. See
* {@link Arrays.toString}.
*
* @return the attribute value's string encoding
*/
@Override
public
String
getValue
()
{
return
value
;
}
/**
* Returns the attribute's ASN.1 DER encoding.
*
* @return a clone of the attribute's DER encoding
*/
public
byte
[]
getEncoded
()
{
return
encoded
.
clone
();
}
/**
* Compares this {@code PKCS12Attribute} and a specified object for
* equality.
*
* @param obj the comparison object
*
* @return true if {@code obj} is a {@code PKCS12Attribute} and
* their DER encodings are equal.
*/
@Override
public
boolean
equals
(
Object
obj
)
{
if
(
this
==
obj
)
{
return
true
;
}
if
(!(
obj
instanceof
PKCS12Attribute
))
{
return
false
;
}
return
Arrays
.
equals
(
encoded
,
((
PKCS12Attribute
)
obj
).
getEncoded
());
}
/**
* Returns the hashcode for this {@code PKCS12Attribute}.
* The hash code is computed from its DER encoding.
*
* @return the hash code
*/
@Override
public
int
hashCode
()
{
if
(
hashValue
==
-
1
)
{
Arrays
.
hashCode
(
encoded
);
}
return
hashValue
;
}
/**
* Returns a string representation of this {@code PKCS12Attribute}.
*
* @return a name/value pair separated by an 'equals' symbol
*/
@Override
public
String
toString
()
{
return
(
name
+
"="
+
value
);
}
private
byte
[]
encode
(
ObjectIdentifier
type
,
String
[]
values
)
throws
IOException
{
DerOutputStream
attribute
=
new
DerOutputStream
();
attribute
.
putOID
(
type
);
DerOutputStream
attrContent
=
new
DerOutputStream
();
for
(
String
value
:
values
)
{
if
(
COLON_SEPARATED_HEX_PAIRS
.
matcher
(
value
).
matches
())
{
byte
[]
bytes
=
new
BigInteger
(
value
.
replace
(
":"
,
""
),
16
).
toByteArray
();
if
(
bytes
[
0
]
==
0
)
{
bytes
=
Arrays
.
copyOfRange
(
bytes
,
1
,
bytes
.
length
);
}
attrContent
.
putOctetString
(
bytes
);
}
else
{
attrContent
.
putUTF8String
(
value
);
}
}
attribute
.
write
(
DerValue
.
tag_Set
,
attrContent
);
DerOutputStream
attributeValue
=
new
DerOutputStream
();
attributeValue
.
write
(
DerValue
.
tag_Sequence
,
attribute
);
return
attributeValue
.
toByteArray
();
}
private
void
parse
(
byte
[]
encoded
)
throws
IOException
{
DerInputStream
attributeValue
=
new
DerInputStream
(
encoded
);
DerValue
[]
attrSeq
=
attributeValue
.
getSequence
(
2
);
ObjectIdentifier
type
=
attrSeq
[
0
].
getOID
();
DerInputStream
attrContent
=
new
DerInputStream
(
attrSeq
[
1
].
toByteArray
());
DerValue
[]
attrValueSet
=
attrContent
.
getSet
(
1
);
String
[]
values
=
new
String
[
attrValueSet
.
length
];
String
printableString
;
for
(
int
i
=
0
;
i
<
attrValueSet
.
length
;
i
++)
{
if
(
attrValueSet
[
i
].
tag
==
DerValue
.
tag_OctetString
)
{
values
[
i
]
=
Debug
.
toString
(
attrValueSet
[
i
].
getOctetString
());
}
else
if
((
printableString
=
attrValueSet
[
i
].
getAsString
())
!=
null
)
{
values
[
i
]
=
printableString
;
}
else
if
(
attrValueSet
[
i
].
tag
==
DerValue
.
tag_ObjectId
)
{
values
[
i
]
=
attrValueSet
[
i
].
getOID
().
toString
();
}
else
if
(
attrValueSet
[
i
].
tag
==
DerValue
.
tag_GeneralizedTime
)
{
values
[
i
]
=
attrValueSet
[
i
].
getGeneralizedTime
().
toString
();
}
else
if
(
attrValueSet
[
i
].
tag
==
DerValue
.
tag_UtcTime
)
{
values
[
i
]
=
attrValueSet
[
i
].
getUTCTime
().
toString
();
}
else
if
(
attrValueSet
[
i
].
tag
==
DerValue
.
tag_Integer
)
{
values
[
i
]
=
attrValueSet
[
i
].
getBigInteger
().
toString
();
}
else
if
(
attrValueSet
[
i
].
tag
==
DerValue
.
tag_Boolean
)
{
values
[
i
]
=
String
.
valueOf
(
attrValueSet
[
i
].
getBoolean
());
}
else
{
values
[
i
]
=
Debug
.
toString
(
attrValueSet
[
i
].
getDataBytes
());
}
}
this
.
name
=
type
.
toString
();
this
.
value
=
values
.
length
==
1
?
values
[
0
]
:
Arrays
.
toString
(
values
);
}
}
src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java
浏览文件 @
a77b812a
...
...
@@ -30,27 +30,30 @@ import java.security.AccessController;
import
java.security.MessageDigest
;
import
java.security.NoSuchAlgorithmException
;
import
java.security.Key
;
import
java.security.KeyStore
;
import
java.security.KeyFactory
;
import
java.security.PrivateKey
;
import
java.security.PrivilegedAction
;
import
java.security.KeyStore
;
import
java.security.KeyStoreSpi
;
import
java.security.KeyStoreException
;
import
java.security.PKCS12Attribute
;
import
java.security.PrivateKey
;
import
java.security.PrivilegedAction
;
import
java.security.UnrecoverableEntryException
;
import
java.security.UnrecoverableKeyException
;
import
java.security.Security
;
import
java.security.SecureRandom
;
import
java.security.Security
;
import
java.security.cert.Certificate
;
import
java.security.cert.CertificateFactory
;
import
java.security.cert.X509Certificate
;
import
java.security.cert.CertificateException
;
import
java.security.spec.AlgorithmParameterSpec
;
import
java.security.spec.KeySpec
;
import
java.security.spec.PKCS8EncodedKeySpec
;
import
java.util.*
;
import
java.security.AlgorithmParameters
;
import
javax.crypto.spec.PBEParameterSpec
;
import
javax.crypto.spec.PBEKeySpec
;
import
javax.crypto.spec.SecretKeySpec
;
import
javax.crypto.SecretKeyFactory
;
import
javax.crypto.SecretKey
;
import
javax.crypto.Cipher
;
...
...
@@ -107,11 +110,12 @@ import sun.security.pkcs.EncryptedPrivateKeyInfo;
* OpenSSL PKCS#12 code. All. All.
* ---------------------------------------------------------------------
*
* NOTE:
Currently PKCS12 KeyStore does not support TrustedCertEntries
.
* NOTE:
PKCS12 KeyStore supports PrivateKeyEntry and TrustedCertficateEntry
.
* PKCS#12 is mainly used to deliver private keys with their associated
* certificate chain and aliases. In a PKCS12 keystore, entries are
* identified by the alias, and a localKeyId is required to match the
* private key with the certificate.
* private key with the certificate. Trusted certificate entries are identified
* by the presence of an trustedKeyUsage attribute.
*
* @author Seema Malkani
* @author Jeff Nisewanger
...
...
@@ -136,6 +140,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
private
static
final
int
keyBag
[]
=
{
1
,
2
,
840
,
113549
,
1
,
12
,
10
,
1
,
2
};
private
static
final
int
certBag
[]
=
{
1
,
2
,
840
,
113549
,
1
,
12
,
10
,
1
,
3
};
private
static
final
int
secretBag
[]
=
{
1
,
2
,
840
,
113549
,
1
,
12
,
10
,
1
,
5
};
private
static
final
int
pkcs9Name
[]
=
{
1
,
2
,
840
,
113549
,
1
,
9
,
20
};
private
static
final
int
pkcs9KeyId
[]
=
{
1
,
2
,
840
,
113549
,
1
,
9
,
21
};
...
...
@@ -147,15 +152,26 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
private
static
final
int
pbeWithSHAAnd3KeyTripleDESCBC
[]
=
{
1
,
2
,
840
,
113549
,
1
,
12
,
1
,
3
};
private
static
final
int
pbes2
[]
=
{
1
,
2
,
840
,
113549
,
1
,
5
,
13
};
// TODO: temporary Oracle OID
/*
* { joint-iso-itu-t(2) country(16) us(840) organization(1) oracle(113894)
* jdk(746875) crypto(1) id-at-trustedKeyUsage(1) }
*/
private
static
final
int
TrustedKeyUsage
[]
=
{
2
,
16
,
840
,
1
,
113894
,
746875
,
1
,
1
};
private
static
final
int
AnyExtendedKeyUsage
[]
=
{
2
,
5
,
29
,
37
,
0
};
private
static
ObjectIdentifier
PKCS8ShroudedKeyBag_OID
;
private
static
ObjectIdentifier
CertBag_OID
;
private
static
ObjectIdentifier
SecretBag_OID
;
private
static
ObjectIdentifier
PKCS9FriendlyName_OID
;
private
static
ObjectIdentifier
PKCS9LocalKeyId_OID
;
private
static
ObjectIdentifier
PKCS9CertType_OID
;
private
static
ObjectIdentifier
pbeWithSHAAnd40BitRC2CBC_OID
;
private
static
ObjectIdentifier
pbeWithSHAAnd3KeyTripleDESCBC_OID
;
private
static
ObjectIdentifier
pbes2_OID
;
private
static
ObjectIdentifier
TrustedKeyUsage_OID
;
private
static
ObjectIdentifier
[]
AnyUsage
;
private
int
counter
=
0
;
private
static
final
int
iterationCount
=
1024
;
...
...
@@ -166,6 +182,12 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
// in pkcs12 with one private key entry and associated cert-chain
private
int
privateKeyCount
=
0
;
// secret key count
private
int
secretKeyCount
=
0
;
// certificate count
private
int
certificateCount
=
0
;
// the source of randomness
private
SecureRandom
random
;
...
...
@@ -173,6 +195,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
try
{
PKCS8ShroudedKeyBag_OID
=
new
ObjectIdentifier
(
keyBag
);
CertBag_OID
=
new
ObjectIdentifier
(
certBag
);
SecretBag_OID
=
new
ObjectIdentifier
(
secretBag
);
PKCS9FriendlyName_OID
=
new
ObjectIdentifier
(
pkcs9Name
);
PKCS9LocalKeyId_OID
=
new
ObjectIdentifier
(
pkcs9KeyId
);
PKCS9CertType_OID
=
new
ObjectIdentifier
(
pkcs9certType
);
...
...
@@ -181,38 +204,67 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
pbeWithSHAAnd3KeyTripleDESCBC_OID
=
new
ObjectIdentifier
(
pbeWithSHAAnd3KeyTripleDESCBC
);
pbes2_OID
=
new
ObjectIdentifier
(
pbes2
);
TrustedKeyUsage_OID
=
new
ObjectIdentifier
(
TrustedKeyUsage
);
AnyUsage
=
new
ObjectIdentifier
[]{
new
ObjectIdentifier
(
AnyExtendedKeyUsage
)};
}
catch
(
IOException
ioe
)
{
// should not happen
}
}
//
Private keys and their supporting certificate chain
s
private
static
class
Key
Entry
{
//
A keystore entry and associated attribute
s
private
static
class
Entry
{
Date
date
;
// the creation date of this entry
String
alias
;
byte
[]
keyId
;
Set
<
KeyStore
.
Entry
.
Attribute
>
attributes
;
}
// A key entry
private
static
class
KeyEntry
extends
Entry
{
}
// A private key entry and its supporting certificate chain
private
static
class
PrivateKeyEntry
extends
KeyEntry
{
byte
[]
protectedPrivKey
;
Certificate
chain
[];
byte
[]
keyId
;
String
alias
;
};
// A certificate with its PKCS #9 attributes
private
static
class
CertEntry
{
// A secret key
private
static
class
SecretKeyEntry
extends
KeyEntry
{
byte
[]
protectedSecretKey
;
};
// A certificate entry
private
static
class
CertEntry
extends
Entry
{
final
X509Certificate
cert
;
final
byte
[]
keyId
;
final
String
alias
;
ObjectIdentifier
[]
trustedKeyUsage
;
CertEntry
(
X509Certificate
cert
,
byte
[]
keyId
,
String
alias
)
{
this
(
cert
,
keyId
,
alias
,
null
,
null
);
}
CertEntry
(
X509Certificate
cert
,
byte
[]
keyId
,
String
alias
,
ObjectIdentifier
[]
trustedKeyUsage
,
Set
<?
extends
KeyStore
.
Entry
.
Attribute
>
attributes
)
{
this
.
date
=
new
Date
();
this
.
cert
=
cert
;
this
.
keyId
=
keyId
;
this
.
alias
=
alias
;
this
.
trustedKeyUsage
=
trustedKeyUsage
;
this
.
attributes
=
new
HashSet
<>();
if
(
attributes
!=
null
)
{
this
.
attributes
.
addAll
(
attributes
);
}
}
}
/**
* Private keys and certificates are stored in a
hashtable
.
*
Hash
entries are keyed by alias names.
* Private keys and certificates are stored in a
map
.
*
Map
entries are keyed by alias names.
*/
private
Hashtable
<
String
,
Key
Entry
>
entries
=
new
Hashtable
<
String
,
KeyEntry
>(
);
private
Map
<
String
,
Entry
>
entries
=
Collections
.
synchronizedMap
(
new
LinkedHashMap
<
String
,
Entry
>()
);
private
ArrayList
<
KeyEntry
>
keyList
=
new
ArrayList
<
KeyEntry
>();
private
LinkedHashMap
<
X500Principal
,
X509Certificate
>
certsMap
=
...
...
@@ -237,15 +289,22 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
public
Key
engineGetKey
(
String
alias
,
char
[]
password
)
throws
NoSuchAlgorithmException
,
UnrecoverableKeyException
{
Key
Entry
entry
=
entries
.
get
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
));
Entry
entry
=
entries
.
get
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
));
Key
key
=
null
;
if
(
entry
==
null
)
{
if
(
entry
==
null
||
(!(
entry
instanceof
KeyEntry
))
)
{
return
null
;
}
// get the encoded private key
byte
[]
encrBytes
=
entry
.
protectedPrivKey
;
// get the encoded private key or secret key
byte
[]
encrBytes
=
null
;
if
(
entry
instanceof
PrivateKeyEntry
)
{
encrBytes
=
((
PrivateKeyEntry
)
entry
).
protectedPrivKey
;
}
else
if
(
entry
instanceof
SecretKeyEntry
)
{
encrBytes
=
((
SecretKeyEntry
)
entry
).
protectedSecretKey
;
}
else
{
throw
new
UnrecoverableKeyException
(
"Error locating key"
);
}
byte
[]
encryptedKey
;
AlgorithmParameters
algParams
;
...
...
@@ -271,14 +330,14 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
}
try
{
byte
[]
privateK
eyInfo
;
byte
[]
k
eyInfo
;
while
(
true
)
{
try
{
// Use JCE
SecretKey
skey
=
getPBEKey
(
password
);
Cipher
cipher
=
Cipher
.
getInstance
(
algOid
.
toString
());
cipher
.
init
(
Cipher
.
DECRYPT_MODE
,
skey
,
algParams
);
privateK
eyInfo
=
cipher
.
doFinal
(
encryptedKey
);
k
eyInfo
=
cipher
.
doFinal
(
encryptedKey
);
break
;
}
catch
(
Exception
e
)
{
if
(
password
.
length
==
0
)
{
...
...
@@ -291,27 +350,52 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
}
}
PKCS8EncodedKeySpec
kspec
=
new
PKCS8EncodedKeySpec
(
privateKeyInfo
);
/*
* Parse the key algorithm and then use a JCA key factory
* to
create the privat
e key.
* to
re-create th
e key.
*/
DerValue
val
=
new
DerValue
(
privateK
eyInfo
);
DerValue
val
=
new
DerValue
(
k
eyInfo
);
DerInputStream
in
=
val
.
toDerInputStream
();
int
i
=
in
.
getInteger
();
DerValue
[]
value
=
in
.
getSequence
(
2
);
AlgorithmId
algId
=
new
AlgorithmId
(
value
[
0
].
getOID
());
String
algName
=
algId
.
getName
();
String
keyAlgo
=
algId
.
getName
();
KeyFactory
kfac
=
KeyFactory
.
getInstance
(
algName
);
key
=
kfac
.
generatePrivate
(
kspec
);
// decode private key
if
(
entry
instanceof
PrivateKeyEntry
)
{
KeyFactory
kfac
=
KeyFactory
.
getInstance
(
keyAlgo
);
PKCS8EncodedKeySpec
kspec
=
new
PKCS8EncodedKeySpec
(
keyInfo
);
key
=
kfac
.
generatePrivate
(
kspec
);
if
(
debug
!=
null
)
{
debug
.
println
(
"Retrieved a protected private key at alias '"
+
alias
+
"'"
);
}
if
(
debug
!=
null
)
{
debug
.
println
(
"Retrieved a protected private key ("
+
key
.
getClass
().
getName
()
+
") at alias '"
+
alias
+
"'"
);
}
// decode secret key
}
else
{
SecretKeyFactory
sKeyFactory
=
SecretKeyFactory
.
getInstance
(
keyAlgo
);
byte
[]
keyBytes
=
in
.
getOctetString
();
SecretKeySpec
secretKeySpec
=
new
SecretKeySpec
(
keyBytes
,
keyAlgo
);
// Special handling required for PBE: needs a PBEKeySpec
if
(
keyAlgo
.
startsWith
(
"PBE"
))
{
KeySpec
pbeKeySpec
=
sKeyFactory
.
getKeySpec
(
secretKeySpec
,
PBEKeySpec
.
class
);
key
=
sKeyFactory
.
generateSecret
(
pbeKeySpec
);
}
else
{
key
=
sKeyFactory
.
generateSecret
(
secretKeySpec
);
}
if
(
debug
!=
null
)
{
debug
.
println
(
"Retrieved a protected secret key ("
+
key
.
getClass
().
getName
()
+
") at alias '"
+
alias
+
"'"
);
}
}
}
catch
(
Exception
e
)
{
UnrecoverableKeyException
uke
=
new
UnrecoverableKeyException
(
"Get Key failed: "
+
...
...
@@ -334,19 +418,19 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
* <i>key entry</i> without a certificate chain).
*/
public
Certificate
[]
engineGetCertificateChain
(
String
alias
)
{
Key
Entry
entry
=
entries
.
get
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
));
if
(
entry
!=
null
)
{
if
(
entry
.
chain
==
null
)
{
Entry
entry
=
entries
.
get
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
));
if
(
entry
!=
null
&&
entry
instanceof
PrivateKeyEntry
)
{
if
(
((
PrivateKeyEntry
)
entry
)
.
chain
==
null
)
{
return
null
;
}
else
{
if
(
debug
!=
null
)
{
debug
.
println
(
"Retrieved a "
+
entry
.
chain
.
length
+
((
PrivateKeyEntry
)
entry
)
.
chain
.
length
+
"-certificate chain at alias '"
+
alias
+
"'"
);
}
return
entry
.
chain
.
clone
();
return
((
PrivateKeyEntry
)
entry
)
.
chain
.
clone
();
}
}
else
{
return
null
;
...
...
@@ -369,9 +453,28 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
* does not contain a certificate.
*/
public
Certificate
engineGetCertificate
(
String
alias
)
{
KeyEntry
entry
=
entries
.
get
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
));
if
(
entry
!=
null
)
{
if
(
entry
.
chain
==
null
)
{
Entry
entry
=
entries
.
get
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
));
if
(
entry
==
null
)
{
return
null
;
}
if
(
entry
instanceof
CertEntry
&&
((
CertEntry
)
entry
).
trustedKeyUsage
!=
null
)
{
if
(
debug
!=
null
)
{
if
(
Arrays
.
equals
(
AnyUsage
,
((
CertEntry
)
entry
).
trustedKeyUsage
))
{
debug
.
println
(
"Retrieved a certificate at alias '"
+
alias
+
"' (trusted for any purpose)"
);
}
else
{
debug
.
println
(
"Retrieved a certificate at alias '"
+
alias
+
"' (trusted for limited purposes)"
);
}
}
return
((
CertEntry
)
entry
).
cert
;
}
else
if
(
entry
instanceof
PrivateKeyEntry
)
{
if
(((
PrivateKeyEntry
)
entry
).
chain
==
null
)
{
return
null
;
}
else
{
...
...
@@ -380,8 +483,9 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
"'"
);
}
return
entry
.
chain
[
0
];
return
((
PrivateKeyEntry
)
entry
)
.
chain
[
0
];
}
}
else
{
return
null
;
}
...
...
@@ -396,7 +500,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
* not exist
*/
public
Date
engineGetCreationDate
(
String
alias
)
{
Key
Entry
entry
=
entries
.
get
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
));
Entry
entry
=
entries
.
get
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
));
if
(
entry
!=
null
)
{
return
new
Date
(
entry
.
date
.
getTime
());
}
else
{
...
...
@@ -434,7 +538,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
new
KeyStore
.
PasswordProtection
(
password
);
try
{
setKeyEntry
(
alias
,
key
,
passwordProtection
,
chain
);
setKeyEntry
(
alias
,
key
,
passwordProtection
,
chain
,
null
);
}
finally
{
try
{
...
...
@@ -446,57 +550,94 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
}
/*
* Sets a key entry
* Sets a key entry
(with attributes, when present)
*/
private
void
setKeyEntry
(
String
alias
,
Key
key
,
KeyStore
.
PasswordProtection
passwordProtection
,
Certificate
[]
chain
)
KeyStore
.
PasswordProtection
passwordProtection
,
Certificate
[]
chain
,
Set
<
KeyStore
.
Entry
.
Attribute
>
attributes
)
throws
KeyStoreException
{
try
{
KeyEntry
entry
=
new
KeyEntry
();
entry
.
date
=
new
Date
();
Entry
entry
;
if
(
key
instanceof
PrivateKey
)
{
PrivateKeyEntry
keyEntry
=
new
PrivateKeyEntry
();
keyEntry
.
date
=
new
Date
();
if
((
key
.
getFormat
().
equals
(
"PKCS#8"
))
||
(
key
.
getFormat
().
equals
(
"PKCS8"
)))
{
// Encrypt the private key
if
(
debug
!=
null
)
{
debug
.
println
(
"Setting a protected private key at "
+
"alias '"
+
alias
+
"'"
);
}
debug
.
println
(
"Setting a protected private key ("
+
key
.
getClass
().
getName
()
+
") at alias '"
+
alias
+
"'"
);
}
entry
.
protectedPrivKey
=
// Encrypt the private key
keyEntry
.
protectedPrivKey
=
encryptPrivateKey
(
key
.
getEncoded
(),
passwordProtection
);
}
else
{
throw
new
KeyStoreException
(
"Private key is not encoded"
+
"as PKCS#8"
);
}
}
else
{
throw
new
KeyStoreException
(
"Key is not a PrivateKey"
);
}
// clone the chain
if
(
chain
!=
null
)
{
// validate cert-chain
if
((
chain
.
length
>
1
)
&&
(!
validateChain
(
chain
)))
throw
new
KeyStoreException
(
"Certificate chain is "
+
"not validate"
);
entry
.
chain
=
chain
.
clone
();
// clone the chain
if
(
chain
!=
null
)
{
// validate cert-chain
if
((
chain
.
length
>
1
)
&&
(!
validateChain
(
chain
)))
throw
new
KeyStoreException
(
"Certificate chain is "
+
"not valid"
);
keyEntry
.
chain
=
chain
.
clone
();
certificateCount
+=
chain
.
length
;
if
(
debug
!=
null
)
{
debug
.
println
(
"Setting a "
+
chain
.
length
+
"-certificate chain at alias '"
+
alias
+
"'"
);
}
}
privateKeyCount
++;
entry
=
keyEntry
;
}
else
if
(
key
instanceof
SecretKey
)
{
SecretKeyEntry
keyEntry
=
new
SecretKeyEntry
();
keyEntry
.
date
=
new
Date
();
// Encode secret key in a PKCS#8
DerOutputStream
pkcs8
=
new
DerOutputStream
();
DerOutputStream
secretKeyInfo
=
new
DerOutputStream
();
secretKeyInfo
.
putInteger
(
0
);
AlgorithmId
algId
=
AlgorithmId
.
get
(
key
.
getAlgorithm
());
algId
.
encode
(
secretKeyInfo
);
secretKeyInfo
.
putOctetString
(
key
.
getEncoded
());
pkcs8
.
write
(
DerValue
.
tag_Sequence
,
secretKeyInfo
);
// Encrypt the secret key (using same PBE as for private keys)
keyEntry
.
protectedSecretKey
=
encryptPrivateKey
(
pkcs8
.
toByteArray
(),
passwordProtection
);
if
(
debug
!=
null
)
{
debug
.
println
(
"Setting a "
+
chain
.
length
+
"-certificate chain at alias '"
+
alias
+
"'"
);
debug
.
println
(
"Setting a protected secret key ("
+
key
.
getClass
().
getName
()
+
") at alias '"
+
alias
+
"'"
);
}
secretKeyCount
++;
entry
=
keyEntry
;
}
else
{
throw
new
KeyStoreException
(
"Unsupported Key type"
);
}
entry
.
attributes
=
new
HashSet
<>();
if
(
attributes
!=
null
)
{
entry
.
attributes
.
addAll
(
attributes
);
}
// set the keyId to current date
entry
.
keyId
=
(
"Time "
+
(
entry
.
date
).
getTime
()).
getBytes
(
"UTF8"
);
// set the alias
entry
.
alias
=
alias
.
toLowerCase
(
Locale
.
ENGLISH
);
// add the entry
entries
.
put
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
),
entry
);
}
catch
(
Exception
nsae
)
{
throw
new
KeyStoreException
(
"Key protection "
+
" algorithm not found: "
+
nsae
,
nsae
);
...
...
@@ -530,7 +671,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
Certificate
[]
chain
)
throws
KeyStoreException
{
// key must be encoded as EncryptedPrivateKeyInfo
//
Private
key must be encoded as EncryptedPrivateKeyInfo
// as defined in PKCS#8
try
{
new
EncryptedPrivateKeyInfo
(
key
);
...
...
@@ -539,11 +680,12 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
+
" as PKCS#8 EncryptedPrivateKeyInfo: "
+
ioe
,
ioe
);
}
KeyEntry
entry
=
new
KeyEntry
();
PrivateKeyEntry
entry
=
new
Private
KeyEntry
();
entry
.
date
=
new
Date
();
if
(
debug
!=
null
)
{
debug
.
println
(
"Setting a protected key at alias '"
+
alias
+
"'"
);
debug
.
println
(
"Setting a protected private key at alias '"
+
alias
+
"'"
);
}
try
{
...
...
@@ -557,7 +699,8 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
entry
.
protectedPrivKey
=
key
.
clone
();
if
(
chain
!=
null
)
{
entry
.
chain
=
chain
.
clone
();
entry
.
chain
=
chain
.
clone
();
certificateCount
+=
chain
.
length
;
if
(
debug
!=
null
)
{
debug
.
println
(
"Setting a "
+
entry
.
chain
.
length
+
...
...
@@ -566,6 +709,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
}
// add the entry
privateKeyCount
++;
entries
.
put
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
),
entry
);
}
...
...
@@ -644,6 +788,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
PBEKeySpec
keySpec
=
new
PBEKeySpec
(
password
);
SecretKeyFactory
skFac
=
SecretKeyFactory
.
getInstance
(
"PBE"
);
skey
=
skFac
.
generateSecret
(
keySpec
);
keySpec
.
clearPassword
();
}
catch
(
Exception
e
)
{
throw
new
IOException
(
"getSecretKey failed: "
+
e
.
getMessage
(),
e
);
...
...
@@ -695,7 +840,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
new
PrivilegedAction
<
String
>()
{
public
String
run
()
{
String
prop
=
Security
.
getProperty
(
Security
.
getProperty
KEY_PROTECTION_ALGORITHM
[
0
]);
if
(
prop
==
null
)
{
prop
=
Security
.
getProperty
(
...
...
@@ -762,17 +907,36 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
* @param cert the certificate
*
* @exception KeyStoreException if the given alias already exists and does
*
identify a <i>key entry</i>, or on an attempt to create a
*
<i>trusted cert entry</i> which is currently not supported
.
*
not identify a <i>trusted certificate entry</i>, or this operation fails
*
for some other reason
.
*/
public
synchronized
void
engineSetCertificateEntry
(
String
alias
,
Certificate
cert
)
throws
KeyStoreException
{
KeyEntry
entry
=
entries
.
get
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
));
if
(
entry
!=
null
)
{
setCertEntry
(
alias
,
cert
,
null
);
}
/*
* Sets a trusted cert entry (with attributes, when present)
*/
private
void
setCertEntry
(
String
alias
,
Certificate
cert
,
Set
<
KeyStore
.
Entry
.
Attribute
>
attributes
)
throws
KeyStoreException
{
Entry
entry
=
entries
.
get
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
));
if
(
entry
!=
null
&&
entry
instanceof
KeyEntry
)
{
throw
new
KeyStoreException
(
"Cannot overwrite own certificate"
);
}
else
throw
new
KeyStoreException
(
"TrustedCertEntry not supported"
);
}
CertEntry
certEntry
=
new
CertEntry
((
X509Certificate
)
cert
,
null
,
alias
,
AnyUsage
,
attributes
);
certificateCount
++;
entries
.
put
(
alias
,
certEntry
);
if
(
debug
!=
null
)
{
debug
.
println
(
"Setting a trusted certificate at alias '"
+
alias
+
"'"
);
}
}
/**
...
...
@@ -789,6 +953,18 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
debug
.
println
(
"Removing entry at alias '"
+
alias
+
"'"
);
}
Entry
entry
=
entries
.
get
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
));
if
(
entry
instanceof
PrivateKeyEntry
)
{
PrivateKeyEntry
keyEntry
=
(
PrivateKeyEntry
)
entry
;
if
(
keyEntry
.
chain
!=
null
)
{
certificateCount
-=
keyEntry
.
chain
.
length
;
}
privateKeyCount
--;
}
else
if
(
entry
instanceof
CertEntry
)
{
certificateCount
--;
}
else
if
(
entry
instanceof
SecretKeyEntry
)
{
secretKeyCount
--;
}
entries
.
remove
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
));
}
...
...
@@ -798,7 +974,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
* @return enumeration of the alias names
*/
public
Enumeration
<
String
>
engineAliases
()
{
return
entries
.
keys
(
);
return
Collections
.
enumeration
(
entries
.
keySet
()
);
}
/**
...
...
@@ -829,8 +1005,8 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
* <i>key entry</i>, false otherwise.
*/
public
boolean
engineIsKeyEntry
(
String
alias
)
{
Key
Entry
entry
=
entries
.
get
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
));
if
(
entry
!=
null
)
{
Entry
entry
=
entries
.
get
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
));
if
(
entry
!=
null
&&
entry
instanceof
KeyEntry
)
{
return
true
;
}
else
{
return
false
;
...
...
@@ -845,8 +1021,13 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
* <i>trusted certificate entry</i>, false otherwise.
*/
public
boolean
engineIsCertificateEntry
(
String
alias
)
{
// TrustedCertEntry is not supported
return
false
;
Entry
entry
=
entries
.
get
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
));
if
(
entry
!=
null
&&
entry
instanceof
CertEntry
&&
((
CertEntry
)
entry
).
trustedKeyUsage
!=
null
)
{
return
true
;
}
else
{
return
false
;
}
}
/**
...
...
@@ -868,11 +1049,18 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
public
String
engineGetCertificateAlias
(
Certificate
cert
)
{
Certificate
certElem
=
null
;
for
(
Enumeration
<
String
>
e
=
en
tries
.
key
s
();
e
.
hasMoreElements
();
)
{
for
(
Enumeration
<
String
>
e
=
en
gineAliase
s
();
e
.
hasMoreElements
();
)
{
String
alias
=
e
.
nextElement
();
KeyEntry
entry
=
entries
.
get
(
alias
);
if
(
entry
.
chain
!=
null
)
{
certElem
=
entry
.
chain
[
0
];
Entry
entry
=
entries
.
get
(
alias
);
if
(
entry
instanceof
PrivateKeyEntry
)
{
if
(((
PrivateKeyEntry
)
entry
).
chain
!=
null
)
{
certElem
=
((
PrivateKeyEntry
)
entry
).
chain
[
0
];
}
}
else
if
(
entry
instanceof
CertEntry
&&
((
CertEntry
)
entry
).
trustedKeyUsage
!=
null
)
{
certElem
=
((
CertEntry
)
entry
).
cert
;
}
else
{
continue
;
}
if
(
certElem
.
equals
(
cert
))
{
return
alias
;
...
...
@@ -918,26 +1106,32 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
DerOutputStream
authSafeContentInfo
=
new
DerOutputStream
();
// -- create safeContent Data ContentInfo
if
(
debug
!=
null
)
{
debug
.
println
(
"Storing "
+
privateKeyCount
+
" protected key(s) in a PKCS#7 data content-type"
);
}
if
(
privateKeyCount
>
0
||
secretKeyCount
>
0
)
{
byte
[]
safeContentData
=
createSafeContent
();
ContentInfo
dataContentInfo
=
new
ContentInfo
(
safeContentData
);
dataContentInfo
.
encode
(
authSafeContentInfo
);
if
(
debug
!=
null
)
{
debug
.
println
(
"Storing "
+
privateKeyCount
+
" protected key(s) in a PKCS#7 data content-type"
);
}
// -- create EncryptedContentInfo
if
(
debug
!=
null
)
{
debug
.
println
(
"Storing certificate(s) in a PKCS#7 encryptedData "
+
"content-type"
);
byte
[]
safeContentData
=
createSafeContent
();
ContentInfo
dataContentInfo
=
new
ContentInfo
(
safeContentData
);
dataContentInfo
.
encode
(
authSafeContentInfo
);
}
byte
[]
encrData
=
createEncryptedData
(
password
);
ContentInfo
encrContentInfo
=
// -- create EncryptedContentInfo
if
(
certificateCount
>
0
)
{
if
(
debug
!=
null
)
{
debug
.
println
(
"Storing "
+
certificateCount
+
" certificate(s) in a PKCS#7 encryptedData content-type"
);
}
byte
[]
encrData
=
createEncryptedData
(
password
);
ContentInfo
encrContentInfo
=
new
ContentInfo
(
ContentInfo
.
ENCRYPTED_DATA_OID
,
new
DerValue
(
encrData
));
encrContentInfo
.
encode
(
authSafeContentInfo
);
encrContentInfo
.
encode
(
authSafeContentInfo
);
}
// wrap as SequenceOf ContentInfos
DerOutputStream
cInfo
=
new
DerOutputStream
();
...
...
@@ -962,6 +1156,207 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
stream
.
flush
();
}
/**
* Gets a <code>KeyStore.Entry</code> for the specified alias
* with the specified protection parameter.
*
* @param alias get the <code>KeyStore.Entry</code> for this alias
* @param protParam the <code>ProtectionParameter</code>
* used to protect the <code>Entry</code>,
* which may be <code>null</code>
*
* @return the <code>KeyStore.Entry</code> for the specified alias,
* or <code>null</code> if there is no such entry
*
* @exception KeyStoreException if the operation failed
* @exception NoSuchAlgorithmException if the algorithm for recovering the
* entry cannot be found
* @exception UnrecoverableEntryException if the specified
* <code>protParam</code> were insufficient or invalid
* @exception UnrecoverableKeyException if the entry is a
* <code>PrivateKeyEntry</code> or <code>SecretKeyEntry</code>
* and the specified <code>protParam</code> does not contain
* the information needed to recover the key (e.g. wrong password)
*
* @since 1.5
*/
@Override
public
KeyStore
.
Entry
engineGetEntry
(
String
alias
,
KeyStore
.
ProtectionParameter
protParam
)
throws
KeyStoreException
,
NoSuchAlgorithmException
,
UnrecoverableEntryException
{
if
(!
engineContainsAlias
(
alias
))
{
return
null
;
}
Entry
entry
=
entries
.
get
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
));
if
(
protParam
==
null
)
{
if
(
engineIsCertificateEntry
(
alias
))
{
if
(
entry
instanceof
CertEntry
&&
((
CertEntry
)
entry
).
trustedKeyUsage
!=
null
)
{
if
(
debug
!=
null
)
{
debug
.
println
(
"Retrieved a trusted certificate at "
+
"alias '"
+
alias
+
"'"
);
}
return
new
KeyStore
.
TrustedCertificateEntry
(
((
CertEntry
)
entry
).
cert
,
getAttributes
(
entry
));
}
}
else
{
throw
new
UnrecoverableKeyException
(
"requested entry requires a password"
);
}
}
if
(
protParam
instanceof
KeyStore
.
PasswordProtection
)
{
if
(
engineIsCertificateEntry
(
alias
))
{
throw
new
UnsupportedOperationException
(
"trusted certificate entries are not password-protected"
);
}
else
if
(
engineIsKeyEntry
(
alias
))
{
KeyStore
.
PasswordProtection
pp
=
(
KeyStore
.
PasswordProtection
)
protParam
;
char
[]
password
=
pp
.
getPassword
();
Key
key
=
engineGetKey
(
alias
,
password
);
if
(
key
instanceof
PrivateKey
)
{
Certificate
[]
chain
=
engineGetCertificateChain
(
alias
);
return
new
KeyStore
.
PrivateKeyEntry
((
PrivateKey
)
key
,
chain
,
getAttributes
(
entry
));
}
else
if
(
key
instanceof
SecretKey
)
{
return
new
KeyStore
.
SecretKeyEntry
((
SecretKey
)
key
,
getAttributes
(
entry
));
}
}
else
if
(!
engineIsKeyEntry
(
alias
))
{
throw
new
UnsupportedOperationException
(
"untrusted certificate entries are not "
+
"password-protected"
);
}
}
throw
new
UnsupportedOperationException
();
}
/**
* Saves a <code>KeyStore.Entry</code> under the specified alias.
* The specified protection parameter is used to protect the
* <code>Entry</code>.
*
* <p> If an entry already exists for the specified alias,
* it is overridden.
*
* @param alias save the <code>KeyStore.Entry</code> under this alias
* @param entry the <code>Entry</code> to save
* @param protParam the <code>ProtectionParameter</code>
* used to protect the <code>Entry</code>,
* which may be <code>null</code>
*
* @exception KeyStoreException if this operation fails
*
* @since 1.5
*/
@Override
public
synchronized
void
engineSetEntry
(
String
alias
,
KeyStore
.
Entry
entry
,
KeyStore
.
ProtectionParameter
protParam
)
throws
KeyStoreException
{
// get password
if
(
protParam
!=
null
&&
!(
protParam
instanceof
KeyStore
.
PasswordProtection
))
{
throw
new
KeyStoreException
(
"unsupported protection parameter"
);
}
KeyStore
.
PasswordProtection
pProtect
=
null
;
if
(
protParam
!=
null
)
{
pProtect
=
(
KeyStore
.
PasswordProtection
)
protParam
;
}
// set entry
if
(
entry
instanceof
KeyStore
.
TrustedCertificateEntry
)
{
if
(
protParam
!=
null
&&
pProtect
.
getPassword
()
!=
null
)
{
// pre-1.5 style setCertificateEntry did not allow password
throw
new
KeyStoreException
(
"trusted certificate entries are not password-protected"
);
}
else
{
KeyStore
.
TrustedCertificateEntry
tce
=
(
KeyStore
.
TrustedCertificateEntry
)
entry
;
setCertEntry
(
alias
,
tce
.
getTrustedCertificate
(),
tce
.
getAttributes
());
return
;
}
}
else
if
(
entry
instanceof
KeyStore
.
PrivateKeyEntry
)
{
if
(
pProtect
==
null
||
pProtect
.
getPassword
()
==
null
)
{
// pre-1.5 style setKeyEntry required password
throw
new
KeyStoreException
(
"non-null password required to create PrivateKeyEntry"
);
}
else
{
KeyStore
.
PrivateKeyEntry
pke
=
(
KeyStore
.
PrivateKeyEntry
)
entry
;
setKeyEntry
(
alias
,
pke
.
getPrivateKey
(),
pProtect
,
pke
.
getCertificateChain
(),
pke
.
getAttributes
());
return
;
}
}
else
if
(
entry
instanceof
KeyStore
.
SecretKeyEntry
)
{
if
(
pProtect
==
null
||
pProtect
.
getPassword
()
==
null
)
{
// pre-1.5 style setKeyEntry required password
throw
new
KeyStoreException
(
"non-null password required to create SecretKeyEntry"
);
}
else
{
KeyStore
.
SecretKeyEntry
ske
=
(
KeyStore
.
SecretKeyEntry
)
entry
;
setKeyEntry
(
alias
,
ske
.
getSecretKey
(),
pProtect
,
(
Certificate
[])
null
,
ske
.
getAttributes
());
return
;
}
}
throw
new
KeyStoreException
(
"unsupported entry type: "
+
entry
.
getClass
().
getName
());
}
/*
* Assemble the entry attributes
*/
private
Set
<
KeyStore
.
Entry
.
Attribute
>
getAttributes
(
Entry
entry
)
{
if
(
entry
.
attributes
==
null
)
{
entry
.
attributes
=
new
HashSet
<>();
}
// friendlyName
entry
.
attributes
.
add
(
new
PKCS12Attribute
(
PKCS9FriendlyName_OID
.
toString
(),
entry
.
alias
));
// localKeyID
byte
[]
keyIdValue
=
entry
.
keyId
;
if
(
keyIdValue
!=
null
)
{
entry
.
attributes
.
add
(
new
PKCS12Attribute
(
PKCS9LocalKeyId_OID
.
toString
(),
Debug
.
toString
(
keyIdValue
)));
}
// trustedKeyUsage
if
(
entry
instanceof
CertEntry
)
{
ObjectIdentifier
[]
trustedKeyUsageValue
=
((
CertEntry
)
entry
).
trustedKeyUsage
;
if
(
trustedKeyUsageValue
!=
null
)
{
if
(
trustedKeyUsageValue
.
length
==
1
)
{
// omit brackets
entry
.
attributes
.
add
(
new
PKCS12Attribute
(
TrustedKeyUsage_OID
.
toString
(),
trustedKeyUsageValue
[
0
].
toString
()));
}
else
{
// multi-valued
entry
.
attributes
.
add
(
new
PKCS12Attribute
(
TrustedKeyUsage_OID
.
toString
(),
Arrays
.
toString
(
trustedKeyUsageValue
)));
}
}
}
return
entry
.
attributes
;
}
/*
* Generate Hash.
*/
...
...
@@ -1036,11 +1431,12 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
/*
* Create PKCS#12 Attributes, friendlyName
and localKeyId
.
* Create PKCS#12 Attributes, friendlyName
, localKeyId and trustedKeyUsage
.
*
* Although attributes are optional, they could be required.
* For e.g. localKeyId attribute is required to match the
* private key with the associated end-entity certificate.
* The trustedKeyUsage attribute is used to denote a trusted certificate.
*
* PKCS8ShroudedKeyBags include unique localKeyID and friendlyName.
* CertBags may or may not include attributes depending on the type
...
...
@@ -1062,20 +1458,28 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
* friendlyName unique same/ same/ unique
* unique unique/
* null
* trustedKeyUsage - - - true
*
* Note: OpenSSL adds friendlyName for end-entity cert only, and
* removes the localKeyID and friendlyName for CA certs.
* If the CertBag did not have a friendlyName, most vendors will
* add it, and assign it to the DN of the cert.
*/
private
byte
[]
getBagAttributes
(
String
alias
,
byte
[]
keyId
)
throws
IOException
{
private
byte
[]
getBagAttributes
(
String
alias
,
byte
[]
keyId
,
Set
<
KeyStore
.
Entry
.
Attribute
>
attributes
)
throws
IOException
{
return
getBagAttributes
(
alias
,
keyId
,
null
,
attributes
);
}
private
byte
[]
getBagAttributes
(
String
alias
,
byte
[]
keyId
,
ObjectIdentifier
[]
trustedUsage
,
Set
<
KeyStore
.
Entry
.
Attribute
>
attributes
)
throws
IOException
{
byte
[]
localKeyID
=
null
;
byte
[]
friendlyName
=
null
;
byte
[]
trustedKeyUsage
=
null
;
// return null if
both
attributes are null
if
((
alias
==
null
)
&&
(
keyId
==
null
))
{
// return null if
all three
attributes are null
if
((
alias
==
null
)
&&
(
keyId
==
null
)
&&
(
trustedKeyUsage
==
null
)
)
{
return
null
;
}
...
...
@@ -1106,6 +1510,20 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
localKeyID
=
bagAttrValue2
.
toByteArray
();
}
// Encode the trustedKeyUsage oid.
if
(
trustedUsage
!=
null
)
{
DerOutputStream
bagAttr3
=
new
DerOutputStream
();
bagAttr3
.
putOID
(
TrustedKeyUsage_OID
);
DerOutputStream
bagAttrContent3
=
new
DerOutputStream
();
DerOutputStream
bagAttrValue3
=
new
DerOutputStream
();
for
(
ObjectIdentifier
usage
:
trustedUsage
)
{
bagAttrContent3
.
putOID
(
usage
);
}
bagAttr3
.
write
(
DerValue
.
tag_Set
,
bagAttrContent3
);
bagAttrValue3
.
write
(
DerValue
.
tag_Sequence
,
bagAttr3
);
trustedKeyUsage
=
bagAttrValue3
.
toByteArray
();
}
DerOutputStream
attrs
=
new
DerOutputStream
();
if
(
friendlyName
!=
null
)
{
attrs
.
write
(
friendlyName
);
...
...
@@ -1113,11 +1531,20 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
if
(
localKeyID
!=
null
)
{
attrs
.
write
(
localKeyID
);
}
if
(
trustedKeyUsage
!=
null
)
{
attrs
.
write
(
trustedKeyUsage
);
}
if
(
attributes
!=
null
)
{
for
(
KeyStore
.
Entry
.
Attribute
attribute
:
attributes
)
{
attrs
.
write
(((
PKCS12Attribute
)
attribute
).
getEncoded
());
}
}
bagAttrs
.
write
(
DerValue
.
tag_Set
,
attrs
);
return
bagAttrs
.
toByteArray
();
}
/*
* Create EncryptedData content type, that contains EncryptedContentInfo.
* Includes certificates in individual SafeBags of type CertBag.
...
...
@@ -1128,17 +1555,26 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
throws
CertificateException
,
IOException
{
DerOutputStream
out
=
new
DerOutputStream
();
for
(
Enumeration
<
String
>
e
=
en
tries
.
key
s
();
e
.
hasMoreElements
();
)
{
for
(
Enumeration
<
String
>
e
=
en
gineAliase
s
();
e
.
hasMoreElements
();
)
{
String
alias
=
e
.
nextElement
();
Key
Entry
entry
=
entries
.
get
(
alias
);
Entry
entry
=
entries
.
get
(
alias
);
// certificate chain
int
chainLen
;
if
(
entry
.
chain
==
null
)
{
chainLen
=
0
;
}
else
{
chainLen
=
entry
.
chain
.
length
;
int
chainLen
=
1
;
Certificate
[]
certs
=
null
;
if
(
entry
instanceof
PrivateKeyEntry
)
{
PrivateKeyEntry
keyEntry
=
(
PrivateKeyEntry
)
entry
;
if
(
keyEntry
.
chain
==
null
)
{
chainLen
=
0
;
}
else
{
chainLen
=
keyEntry
.
chain
.
length
;
}
certs
=
keyEntry
.
chain
;
}
else
if
(
entry
instanceof
CertEntry
)
{
certs
=
new
Certificate
[]{((
CertEntry
)
entry
).
cert
};
}
for
(
int
i
=
0
;
i
<
chainLen
;
i
++)
{
...
...
@@ -1152,7 +1588,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
// write encoded certs in a context-specific tag
DerOutputStream
certValue
=
new
DerOutputStream
();
X509Certificate
cert
=
(
X509Certificate
)
entry
.
chain
[
i
];
X509Certificate
cert
=
(
X509Certificate
)
certs
[
i
];
certValue
.
putOctetString
(
cert
.
getEncoded
());
certBag
.
write
(
DerValue
.
createTag
(
DerValue
.
TAG_CONTEXT
,
true
,
(
byte
)
0
),
certValue
);
...
...
@@ -1175,7 +1611,18 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
byte
[]
bagAttrs
=
null
;
if
(
i
==
0
)
{
// Only End-Entity Cert should have a localKeyId.
bagAttrs
=
getBagAttributes
(
entry
.
alias
,
entry
.
keyId
);
if
(
entry
instanceof
KeyEntry
)
{
KeyEntry
keyEntry
=
(
KeyEntry
)
entry
;
bagAttrs
=
getBagAttributes
(
keyEntry
.
alias
,
keyEntry
.
keyId
,
keyEntry
.
attributes
);
}
else
{
CertEntry
certEntry
=
(
CertEntry
)
entry
;
bagAttrs
=
getBagAttributes
(
certEntry
.
alias
,
certEntry
.
keyId
,
certEntry
.
trustedKeyUsage
,
certEntry
.
attributes
);
}
}
else
{
// Trusted root CA certs and Intermediate CA certs do not
// need to have a localKeyId, and hence localKeyId is null
...
...
@@ -1184,7 +1631,8 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
// certificate chain to have unique or null localKeyID.
// However, IE/OpenSSL do not impose this restriction.
bagAttrs
=
getBagAttributes
(
cert
.
getSubjectX500Principal
().
getName
(),
null
);
cert
.
getSubjectX500Principal
().
getName
(),
null
,
entry
.
attributes
);
}
if
(
bagAttrs
!=
null
)
{
safeBag
.
write
(
bagAttrs
);
...
...
@@ -1214,6 +1662,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
/*
* Create SafeContent Data content type.
* Includes encrypted secret key in a SafeBag of type SecretBag.
* Includes encrypted private key in a SafeBag of type PKCS8ShroudedKeyBag.
* Each PKCS8ShroudedKeyBag includes pkcs12 attributes
* (see comments in getBagAttributes)
...
...
@@ -1222,33 +1671,74 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
throws
CertificateException
,
IOException
{
DerOutputStream
out
=
new
DerOutputStream
();
for
(
Enumeration
<
String
>
e
=
en
tries
.
key
s
();
e
.
hasMoreElements
();
)
{
for
(
Enumeration
<
String
>
e
=
en
gineAliase
s
();
e
.
hasMoreElements
();
)
{
String
alias
=
e
.
nextElement
();
KeyEntry
entry
=
entries
.
get
(
alias
);
// Create SafeBag of type pkcs8ShroudedKeyBag
Entry
entry
=
entries
.
get
(
alias
);
if
(
entry
==
null
||
(!(
entry
instanceof
KeyEntry
)))
{
continue
;
}
DerOutputStream
safeBag
=
new
DerOutputStream
();
safeBag
.
putOID
(
PKCS8ShroudedKeyBag_OID
)
;
KeyEntry
keyEntry
=
(
KeyEntry
)
entry
;
// get the encrypted private key
byte
[]
encrBytes
=
entry
.
protectedPrivKey
;
EncryptedPrivateKeyInfo
encrInfo
=
null
;
try
{
encrInfo
=
new
EncryptedPrivateKeyInfo
(
encrBytes
);
}
catch
(
IOException
ioe
)
{
throw
new
IOException
(
"Private key not stored as "
+
"PKCS#8 EncryptedPrivateKeyInfo"
+
ioe
.
getMessage
());
}
// DER encode the private key
if
(
keyEntry
instanceof
PrivateKeyEntry
)
{
// Create SafeBag of type pkcs8ShroudedKeyBag
safeBag
.
putOID
(
PKCS8ShroudedKeyBag_OID
);
// get the encrypted private key
byte
[]
encrBytes
=
((
PrivateKeyEntry
)
keyEntry
).
protectedPrivKey
;
EncryptedPrivateKeyInfo
encrInfo
=
null
;
try
{
encrInfo
=
new
EncryptedPrivateKeyInfo
(
encrBytes
);
// Wrap the EncryptedPrivateKeyInfo in a context-specific tag.
DerOutputStream
bagValue
=
new
DerOutputStream
();
bagValue
.
write
(
encrInfo
.
getEncoded
());
safeBag
.
write
(
DerValue
.
createTag
(
DerValue
.
TAG_CONTEXT
,
}
catch
(
IOException
ioe
)
{
throw
new
IOException
(
"Private key not stored as "
+
"PKCS#8 EncryptedPrivateKeyInfo"
+
ioe
.
getMessage
());
}
// Wrap the EncryptedPrivateKeyInfo in a context-specific tag.
DerOutputStream
bagValue
=
new
DerOutputStream
();
bagValue
.
write
(
encrInfo
.
getEncoded
());
safeBag
.
write
(
DerValue
.
createTag
(
DerValue
.
TAG_CONTEXT
,
true
,
(
byte
)
0
),
bagValue
);
// DER encode the secret key
}
else
if
(
keyEntry
instanceof
SecretKeyEntry
)
{
// Create SafeBag of type SecretBag
safeBag
.
putOID
(
SecretBag_OID
);
// Create a SecretBag
DerOutputStream
secretBag
=
new
DerOutputStream
();
secretBag
.
putOID
(
PKCS8ShroudedKeyBag_OID
);
// Write secret key in a context-specific tag
DerOutputStream
secretKeyValue
=
new
DerOutputStream
();
secretKeyValue
.
putOctetString
(
((
SecretKeyEntry
)
keyEntry
).
protectedSecretKey
);
secretBag
.
write
(
DerValue
.
createTag
(
DerValue
.
TAG_CONTEXT
,
true
,
(
byte
)
0
),
secretKeyValue
);
// Wrap SecretBag in a Sequence
DerOutputStream
secretBagSeq
=
new
DerOutputStream
();
secretBagSeq
.
write
(
DerValue
.
tag_Sequence
,
secretBag
);
byte
[]
secretBagValue
=
secretBagSeq
.
toByteArray
();
// Wrap the secret bag in a context-specific tag.
DerOutputStream
bagValue
=
new
DerOutputStream
();
bagValue
.
write
(
secretBagValue
);
// Write SafeBag value
safeBag
.
write
(
DerValue
.
createTag
(
DerValue
.
TAG_CONTEXT
,
true
,
(
byte
)
0
),
bagValue
);
}
else
{
continue
;
// skip this entry
}
// write SafeBag Attributes
byte
[]
bagAttrs
=
getBagAttributes
(
alias
,
entry
.
keyId
);
byte
[]
bagAttrs
=
getBagAttributes
(
alias
,
entry
.
keyId
,
entry
.
attributes
);
safeBag
.
write
(
bagAttrs
);
// wrap as Sequence
...
...
@@ -1377,8 +1867,10 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
DerValue
[]
safeContentsArray
=
as
.
getSequence
(
2
);
int
count
=
safeContentsArray
.
length
;
// reset the count at the start
// reset the count
ers
at the start
privateKeyCount
=
0
;
secretKeyCount
=
0
;
certificateCount
=
0
;
/*
* Spin over the ContentInfos.
...
...
@@ -1445,7 +1937,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
continue
;
}
throw
new
IOException
(
"failed to decrypt safe contents entry: "
+
e
,
e
);
"failed to decrypt safe contents entry: "
+
e
,
e
);
}
}
}
else
{
...
...
@@ -1493,9 +1985,10 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
/*
* Match up private keys with certificate chains.
*/
KeyEntry
[]
list
=
keyList
.
toArray
(
new
KeyEntry
[
keyList
.
size
()]);
PrivateKeyEntry
[]
list
=
keyList
.
toArray
(
new
PrivateKeyEntry
[
keyList
.
size
()]);
for
(
int
m
=
0
;
m
<
list
.
length
;
m
++)
{
KeyEntry
entry
=
list
[
m
];
Private
KeyEntry
entry
=
list
[
m
];
if
(
entry
.
keyId
!=
null
)
{
ArrayList
<
X509Certificate
>
chain
=
new
ArrayList
<
X509Certificate
>();
...
...
@@ -1513,6 +2006,22 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
entry
.
chain
=
chain
.
toArray
(
new
Certificate
[
chain
.
size
()]);
}
}
if
(
debug
!=
null
)
{
if
(
privateKeyCount
>
0
)
{
debug
.
println
(
"Loaded "
+
privateKeyCount
+
" protected private key(s)"
);
}
if
(
secretKeyCount
>
0
)
{
debug
.
println
(
"Loaded "
+
secretKeyCount
+
" protected secret key(s)"
);
}
if
(
certificateCount
>
0
)
{
debug
.
println
(
"Loaded "
+
certificateCount
+
" certificate(s)"
);
}
}
certEntries
.
clear
();
certsMap
.
clear
();
keyList
.
clear
();
...
...
@@ -1523,7 +2032,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
* @param entry the KeyEntry to match
* @return a certificate, null if not found
*/
private
X509Certificate
findMatchedCertificate
(
KeyEntry
entry
)
{
private
X509Certificate
findMatchedCertificate
(
Private
KeyEntry
entry
)
{
CertEntry
keyIdMatch
=
null
;
CertEntry
aliasMatch
=
null
;
for
(
CertEntry
ce:
certEntries
)
{
...
...
@@ -1567,7 +2076,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
}
bagValue
=
bagValue
.
data
.
getDerValue
();
if
(
bagId
.
equals
((
Object
)
PKCS8ShroudedKeyBag_OID
))
{
KeyEntry
kEntry
=
new
KeyEntry
();
PrivateKeyEntry
kEntry
=
new
Private
KeyEntry
();
kEntry
.
protectedPrivKey
=
bagValue
.
toByteArray
();
bagItem
=
kEntry
;
privateKeyCount
++;
...
...
@@ -1585,6 +2094,20 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
cert
=
(
X509Certificate
)
cf
.
generateCertificate
(
new
ByteArrayInputStream
(
certValue
.
getOctetString
()));
bagItem
=
cert
;
certificateCount
++;
}
else
if
(
bagId
.
equals
((
Object
)
SecretBag_OID
))
{
DerInputStream
ss
=
new
DerInputStream
(
bagValue
.
toByteArray
());
DerValue
[]
secretValues
=
ss
.
getSequence
(
2
);
ObjectIdentifier
secretId
=
secretValues
[
0
].
getOID
();
if
(!
secretValues
[
1
].
isContextSpecific
((
byte
)
0
))
{
throw
new
IOException
(
"unsupported PKCS12 secret value type "
+
secretValues
[
1
].
tag
);
}
DerValue
secretValue
=
secretValues
[
1
].
data
.
getDerValue
();
SecretKeyEntry
kEntry
=
new
SecretKeyEntry
();
kEntry
.
protectedSecretKey
=
secretValue
.
getOctetString
();
bagItem
=
kEntry
;
}
else
{
if
(
debug
!=
null
)
{
...
...
@@ -1594,7 +2117,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
DerValue
[]
attrSet
;
try
{
attrSet
=
sbi
.
getSet
(
2
);
attrSet
=
sbi
.
getSet
(
3
);
}
catch
(
IOException
e
)
{
// entry does not have attributes
// Note: CA certs can have no attributes
...
...
@@ -1604,11 +2127,13 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
String
alias
=
null
;
byte
[]
keyId
=
null
;
ObjectIdentifier
[]
trustedKeyUsage
=
null
;
Set
<
PKCS12Attribute
>
attributes
=
new
HashSet
<>();
if
(
attrSet
!=
null
)
{
for
(
int
j
=
0
;
j
<
attrSet
.
length
;
j
++)
{
DerInputStream
as
=
new
DerInputStream
(
attrSet
[
j
].
toByteArray
()
);
byte
[]
encoded
=
attrSet
[
j
].
toByteArray
();
DerInputStream
as
=
new
DerInputStream
(
encoded
);
DerValue
[]
attrSeq
=
as
.
getSequence
(
2
);
ObjectIdentifier
attrId
=
attrSeq
[
0
].
getOID
();
DerInputStream
vs
=
...
...
@@ -1624,12 +2149,14 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
alias
=
valSet
[
0
].
getBMPString
();
}
else
if
(
attrId
.
equals
((
Object
)
PKCS9LocalKeyId_OID
))
{
keyId
=
valSet
[
0
].
getOctetString
();
}
else
{
if
(
debug
!=
null
)
{
debug
.
println
(
"Unsupported PKCS12 bag attribute: "
+
attrId
);
}
else
if
(
attrId
.
equals
((
Object
)
TrustedKeyUsage_OID
))
{
trustedKeyUsage
=
new
ObjectIdentifier
[
valSet
.
length
];
for
(
int
k
=
0
;
k
<
valSet
.
length
;
k
++)
{
trustedKeyUsage
[
k
]
=
valSet
[
k
].
getOID
(
);
}
}
else
{
attributes
.
add
(
new
PKCS12Attribute
(
encoded
));
}
}
}
...
...
@@ -1645,16 +2172,19 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
*/
if
(
bagItem
instanceof
KeyEntry
)
{
KeyEntry
entry
=
(
KeyEntry
)
bagItem
;
if
(
keyId
==
null
)
{
// Insert a localKeyID for the privateKey
// Note: This is a workaround to allow null localKeyID
// attribute in pkcs12 with one private key entry and
// associated cert-chain
if
(
privateKeyCount
==
1
)
{
keyId
=
"01"
.
getBytes
(
"UTF8"
);
}
else
{
continue
;
}
if
(
bagItem
instanceof
PrivateKeyEntry
)
{
if
(
keyId
==
null
)
{
// Insert a localKeyID for the privateKey
// Note: This is a workaround to allow null localKeyID
// attribute in pkcs12 with one private key entry and
// associated cert-chain
if
(
privateKeyCount
==
1
)
{
keyId
=
"01"
.
getBytes
(
"UTF8"
);
}
else
{
continue
;
}
}
}
entry
.
keyId
=
keyId
;
// restore date if it exists
...
...
@@ -1672,11 +2202,16 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
date
=
new
Date
();
}
entry
.
date
=
date
;
keyList
.
add
(
entry
);
if
(
alias
==
null
)
if
(
bagItem
instanceof
PrivateKeyEntry
)
{
keyList
.
add
((
PrivateKeyEntry
)
entry
);
}
if
(
alias
==
null
)
{
alias
=
getUnfriendlyName
();
}
entry
.
alias
=
alias
;
entries
.
put
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
),
entry
);
}
else
if
(
bagItem
instanceof
X509Certificate
)
{
X509Certificate
cert
=
(
X509Certificate
)
bagItem
;
// Insert a localKeyID for the corresponding cert
...
...
@@ -1689,7 +2224,18 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
keyId
=
"01"
.
getBytes
(
"UTF8"
);
}
}
certEntries
.
add
(
new
CertEntry
(
cert
,
keyId
,
alias
));
if
(
alias
==
null
)
{
alias
=
getUnfriendlyName
();
}
// Trusted certificate
if
(
trustedKeyUsage
!=
null
)
{
CertEntry
certEntry
=
new
CertEntry
(
cert
,
keyId
,
alias
,
trustedKeyUsage
,
attributes
);
entries
.
put
(
alias
.
toLowerCase
(
Locale
.
ENGLISH
),
certEntry
);
}
else
{
certEntries
.
add
(
new
CertEntry
(
cert
,
keyId
,
alias
));
}
X500Principal
subjectDN
=
cert
.
getSubjectX500Principal
();
if
(
subjectDN
!=
null
)
{
if
(!
certsMap
.
containsKey
(
subjectDN
))
{
...
...
src/share/classes/sun/security/x509/AlgorithmId.java
浏览文件 @
a77b812a
/*
* Copyright (c) 1996, 201
2
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 201
3
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -502,6 +502,11 @@ public class AlgorithmId implements Serializable, DerEncoder {
return
AlgorithmId
.
ECDH_oid
;
}
// Secret key algorithms
if
(
name
.
equalsIgnoreCase
(
"AES"
))
{
return
AlgorithmId
.
AES_oid
;
}
// Common signature types
if
(
name
.
equalsIgnoreCase
(
"MD5withRSA"
)
||
name
.
equalsIgnoreCase
(
"MD5/RSA"
))
{
...
...
@@ -660,6 +665,12 @@ public class AlgorithmId implements Serializable, DerEncoder {
public
static
final
ObjectIdentifier
RSA_oid
;
public
static
final
ObjectIdentifier
RSAEncryption_oid
;
/*
* COMMON SECRET KEY TYPES
*/
public
static
final
ObjectIdentifier
AES_oid
=
oid
(
2
,
16
,
840
,
1
,
101
,
3
,
4
,
1
);
/*
* COMMON SIGNATURE ALGORITHMS
*/
...
...
@@ -893,6 +904,8 @@ public class AlgorithmId implements Serializable, DerEncoder {
nameTable
.
put
(
EC_oid
,
"EC"
);
nameTable
.
put
(
ECDH_oid
,
"ECDH"
);
nameTable
.
put
(
AES_oid
,
"AES"
);
nameTable
.
put
(
sha1WithECDSA_oid
,
"SHA1withECDSA"
);
nameTable
.
put
(
sha224WithECDSA_oid
,
"SHA224withECDSA"
);
nameTable
.
put
(
sha256WithECDSA_oid
,
"SHA256withECDSA"
);
...
...
test/sun/security/pkcs12/StorePasswordTest.java
0 → 100644
浏览文件 @
a77b812a
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8005408
* @summary KeyStore API enhancements
*/
import
java.io.*
;
import
java.security.*
;
import
java.util.*
;
import
javax.crypto.*
;
import
javax.crypto.spec.*
;
import
java.security.spec.InvalidKeySpecException
;
// Store a password in a keystore and retrieve it again.
public
class
StorePasswordTest
{
private
final
static
String
DIR
=
System
.
getProperty
(
"test.src"
,
"."
);
private
static
final
char
[]
PASSWORD
=
"passphrase"
.
toCharArray
();
private
static
final
String
KEYSTORE
=
"pwdstore.p12"
;
private
static
final
String
ALIAS
=
"my password"
;
private
static
final
String
USER_PASSWORD
=
"hello1"
;
public
static
void
main
(
String
[]
args
)
throws
Exception
{
new
File
(
KEYSTORE
).
delete
();
try
{
KeyStore
keystore
=
KeyStore
.
getInstance
(
"PKCS12"
);
keystore
.
load
(
null
,
null
);
// Set entry
keystore
.
setEntry
(
ALIAS
,
new
KeyStore
.
SecretKeyEntry
(
convertPassword
(
USER_PASSWORD
)),
new
KeyStore
.
PasswordProtection
(
PASSWORD
));
System
.
out
.
println
(
"Storing keystore to: "
+
KEYSTORE
);
keystore
.
store
(
new
FileOutputStream
(
KEYSTORE
),
PASSWORD
);
System
.
out
.
println
(
"Loading keystore from: "
+
KEYSTORE
);
keystore
.
load
(
new
FileInputStream
(
KEYSTORE
),
PASSWORD
);
System
.
out
.
println
(
"Loaded keystore with "
+
keystore
.
size
()
+
" entries"
);
KeyStore
.
Entry
entry
=
keystore
.
getEntry
(
ALIAS
,
new
KeyStore
.
PasswordProtection
(
PASSWORD
));
System
.
out
.
println
(
"Retrieved entry: "
+
entry
);
SecretKey
key
=
(
SecretKey
)
keystore
.
getKey
(
ALIAS
,
PASSWORD
);
SecretKeyFactory
factory
=
SecretKeyFactory
.
getInstance
(
key
.
getAlgorithm
());
PBEKeySpec
keySpec
=
(
PBEKeySpec
)
factory
.
getKeySpec
(
key
,
PBEKeySpec
.
class
);
char
[]
pwd
=
keySpec
.
getPassword
();
System
.
out
.
println
(
"Recovered credential: "
+
new
String
(
pwd
));
if
(!
Arrays
.
equals
(
USER_PASSWORD
.
toCharArray
(),
pwd
))
{
throw
new
Exception
(
"Failed to recover the stored password"
);
}
}
finally
{
new
File
(
KEYSTORE
).
delete
();
}
}
private
static
SecretKey
convertPassword
(
String
password
)
throws
NoSuchAlgorithmException
,
InvalidKeySpecException
{
SecretKeyFactory
factory
=
SecretKeyFactory
.
getInstance
(
"PBE"
);
return
factory
.
generateSecret
(
new
PBEKeySpec
(
password
.
toCharArray
()));
}
}
test/sun/security/pkcs12/StoreSecretKeyTest.java
0 → 100644
浏览文件 @
a77b812a
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8005408
* @summary KeyStore API enhancements
*/
import
java.io.*
;
import
java.security.*
;
import
java.util.*
;
import
javax.crypto.*
;
import
javax.crypto.spec.*
;
// Store a secret key in a keystore and retrieve it again.
public
class
StoreSecretKeyTest
{
private
final
static
String
DIR
=
System
.
getProperty
(
"test.src"
,
"."
);
private
static
final
char
[]
PASSWORD
=
"passphrase"
.
toCharArray
();
private
static
final
String
KEYSTORE
=
"keystore.p12"
;
private
static
final
String
ALIAS
=
"my secret key"
;
public
static
void
main
(
String
[]
args
)
throws
Exception
{
new
File
(
KEYSTORE
).
delete
();
try
{
KeyStore
keystore
=
KeyStore
.
getInstance
(
"PKCS12"
);
keystore
.
load
(
null
,
null
);
// Set entry
keystore
.
setEntry
(
ALIAS
,
new
KeyStore
.
SecretKeyEntry
(
generateSecretKey
(
"AES"
,
128
)),
new
KeyStore
.
PasswordProtection
(
PASSWORD
));
System
.
out
.
println
(
"Storing keystore to: "
+
KEYSTORE
);
keystore
.
store
(
new
FileOutputStream
(
KEYSTORE
),
PASSWORD
);
System
.
out
.
println
(
"Loading keystore from: "
+
KEYSTORE
);
keystore
.
load
(
new
FileInputStream
(
KEYSTORE
),
PASSWORD
);
System
.
out
.
println
(
"Loaded keystore with "
+
keystore
.
size
()
+
" entries"
);
KeyStore
.
Entry
entry
=
keystore
.
getEntry
(
ALIAS
,
new
KeyStore
.
PasswordProtection
(
PASSWORD
));
System
.
out
.
println
(
"Retrieved entry: "
+
entry
);
if
(
entry
instanceof
KeyStore
.
SecretKeyEntry
)
{
System
.
out
.
println
(
"Retrieved secret key entry: "
+
entry
);
}
else
{
throw
new
Exception
(
"Not a secret key entry"
);
}
}
finally
{
new
File
(
KEYSTORE
).
delete
();
}
}
private
static
SecretKey
generateSecretKey
(
String
algorithm
,
int
size
)
throws
NoSuchAlgorithmException
{
KeyGenerator
generator
=
KeyGenerator
.
getInstance
(
algorithm
);
generator
.
init
(
size
);
return
generator
.
generateKey
();
}
}
test/sun/security/pkcs12/StoreTrustedCertTest.java
0 → 100644
浏览文件 @
a77b812a
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8005408
* @summary KeyStore API enhancements
*/
import
java.io.*
;
import
java.security.*
;
import
java.security.cert.*
;
import
java.util.*
;
import
java.security.cert.Certificate
;
import
javax.crypto.*
;
import
javax.crypto.spec.*
;
// Store a trusted certificate in a keystore and retrieve it again.
public
class
StoreTrustedCertTest
{
private
final
static
String
DIR
=
System
.
getProperty
(
"test.src"
,
"."
);
private
static
final
char
[]
PASSWORD
=
"passphrase"
.
toCharArray
();
private
static
final
String
KEYSTORE
=
"truststore.p12"
;
private
static
final
String
CERT
=
DIR
+
"/trusted.pem"
;
private
static
final
String
ALIAS
=
"my trustedcert"
;
private
static
final
String
ALIAS2
=
"my trustedcert with attributes"
;
public
static
void
main
(
String
[]
args
)
throws
Exception
{
new
File
(
KEYSTORE
).
delete
();
try
{
KeyStore
keystore
=
KeyStore
.
getInstance
(
"PKCS12"
);
keystore
.
load
(
null
,
null
);
Certificate
cert
=
loadCertificate
(
CERT
);
Set
<
KeyStore
.
Entry
.
Attribute
>
attributes
=
new
HashSet
<>();
attributes
.
add
(
new
PKCS12Attribute
(
"1.3.5.7.9"
,
"that's odd"
));
attributes
.
add
(
new
PKCS12Attribute
(
"2.4.6.8.10"
,
"that's even"
));
// Set trusted certificate entry
keystore
.
setEntry
(
ALIAS
,
new
KeyStore
.
TrustedCertificateEntry
(
cert
),
null
);
// Set trusted certificate entry with attributes
keystore
.
setEntry
(
ALIAS2
,
new
KeyStore
.
TrustedCertificateEntry
(
cert
,
attributes
),
null
);
System
.
out
.
println
(
"Storing keystore to: "
+
KEYSTORE
);
keystore
.
store
(
new
FileOutputStream
(
KEYSTORE
),
PASSWORD
);
System
.
out
.
println
(
"Loading keystore from: "
+
KEYSTORE
);
keystore
.
load
(
new
FileInputStream
(
KEYSTORE
),
PASSWORD
);
System
.
out
.
println
(
"Loaded keystore with "
+
keystore
.
size
()
+
" entries"
);
KeyStore
.
Entry
entry
=
keystore
.
getEntry
(
ALIAS
,
null
);
if
(
entry
instanceof
KeyStore
.
TrustedCertificateEntry
)
{
System
.
out
.
println
(
"Retrieved trusted certificate entry: "
+
entry
);
}
else
{
throw
new
Exception
(
"Not a trusted certificate entry"
);
}
System
.
out
.
println
();
entry
=
keystore
.
getEntry
(
ALIAS2
,
null
);
if
(
entry
instanceof
KeyStore
.
TrustedCertificateEntry
)
{
KeyStore
.
TrustedCertificateEntry
trustedEntry
=
(
KeyStore
.
TrustedCertificateEntry
)
entry
;
Set
<
KeyStore
.
Entry
.
Attribute
>
entryAttributes
=
trustedEntry
.
getAttributes
();
if
(
entryAttributes
.
containsAll
(
attributes
))
{
System
.
out
.
println
(
"Retrieved trusted certificate entry "
+
"with attributes: "
+
entry
);
}
else
{
throw
new
Exception
(
"Failed to retrieve entry attributes"
);
}
}
else
{
throw
new
Exception
(
"Not a trusted certificate entry"
);
}
}
finally
{
new
File
(
KEYSTORE
).
delete
();
}
}
private
static
Certificate
loadCertificate
(
String
certFile
)
throws
Exception
{
X509Certificate
cert
=
null
;
try
(
FileInputStream
certStream
=
new
FileInputStream
(
certFile
))
{
CertificateFactory
factory
=
CertificateFactory
.
getInstance
(
"X.509"
);
return
factory
.
generateCertificate
(
certStream
);
}
}
}
test/sun/security/pkcs12/trusted.pem
0 → 100644
浏览文件 @
a77b812a
-----BEGIN CERTIFICATE-----
MIIF5DCCBMygAwIBAgIQGVCD3zqdD1ZMZZ/zLAPnQzANBgkqhkiG9w0BAQUFADCBvDELMAkGA1UE
BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
ZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQgaHR0cHM6Ly93d3cudmVyaXNpZ24uY29t
L3JwYSAoYykxMDE2MDQGA1UEAxMtVmVyaVNpZ24gQ2xhc3MgMyBJbnRlcm5hdGlvbmFsIFNlcnZl
ciBDQSAtIEczMB4XDTEyMDcxMDAwMDAwMFoXDTEzMDczMTIzNTk1OVowgbgxCzAJBgNVBAYTAlVT
MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQHFA5SZWR3b29kIFNob3JlczEbMBkGA1UEChQS
T3JhY2xlIENvcnBvcmF0aW9uMRIwEAYDVQQLFAlHbG9iYWwgSVQxMzAxBgNVBAsUKlRlcm1zIG9m
IHVzZSBhdCB3d3cudmVyaXNpZ24uY29tL3JwYSAoYykwNTEVMBMGA1UEAxQMKi5vcmFjbGUuY29t
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz/dOCGrWzPj62q0ZkF59Oj9Fli4wHAuX
U4/S0yBXF8j6K7TKWFTQkGZt3+08KUhmLm1CE1DbbyRJT292YNXYXunNaKdABob8kaBO/NESUOEJ
0SZh7fd0xCSJAAPiwOMrM5jLeb/dEpU6nP74Afrhu5ffvKdcvTRGguj9H2oVsisTK8Z1HsiiwcJG
JXcrjvdCZoPU4FHvK03XZPAqPHKNSaJOrux6kRIWYjQMlmL+qDOb0nNHa6gBdi+VqqJHJHeAM677
dcUd0jn2m2OWtUnrM3MJZQof7/z27RTdX5J8np0ChkUgm63biDgRZO7uZP0DARQ0I6lZMlrarT8/
sct3twIDAQABo4IB4jCCAd4wFwYDVR0RBBAwDoIMKi5vcmFjbGUuY29tMAkGA1UdEwQCMAAwCwYD
VR0PBAQDAgWgMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHFwMwKjAoBggrBgEFBQcCARYcaHR0cHM6
Ly93d3cudmVyaXNpZ24uY29tL3JwYTAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwbgYI
KwYBBQUHAQwEYjBgoV6gXDBaMFgwVhYJaW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUS2u5KJYGDLvQ
UjibKaxLB4shBRgwJhYkaHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nbzEuZ2lmMHIGCCsG
AQUFBwEBBGYwZDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AudmVyaXNpZ24uY29tMDwGCCsGAQUF
BzAChjBodHRwOi8vc3ZyaW50bC1nMy1haWEudmVyaXNpZ24uY29tL1NWUkludGxHMy5jZXIwQQYD
VR0fBDowODA2oDSgMoYwaHR0cDovL3N2cmludGwtZzMtY3JsLnZlcmlzaWduLmNvbS9TVlJJbnRs
RzMuY3JsMB8GA1UdIwQYMBaAFNebfNgioBX33a1fzimbWMO8RgC1MA0GCSqGSIb3DQEBBQUAA4IB
AQAITRBlEo+qXLwCL53Db2BGnhDgnSomjne8aCmU7Yt4Kp91tzJdhNuaC/wwDuzD2dPJqzemae3s
wKiOXrmDQZDj9NNTdkrXHnCvDR4TpOynWe3zBa0bwKnV2cIRKcv482yV53u0kALyFZbagYPwOOz3
YJA/2SqdcDn9Ztc/ABQ1SkyXyA5j4LJdf2g7BtYrFxjy0RG6We2iM781WSB/9MCNKyHgiwd3KpLf
urdSKLzy1elNAyt1P3UHwBIIvZ6sJIr/eeELc54Lxt6PtQCXx8qwxYTYXWPXbLgKBHdebgrmAbPK
TfD69wysvjk6vwSHjmvaqB4R4WRcgkuT+1gxx+ve
-----END CERTIFICATE-----
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录