Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
O
Openfire
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Openfire
Commits
5a52d003
Commit
5a52d003
authored
Nov 30, 2015
by
Guus der Kinderen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Restoring 'import private key & certificate' functionality.
parent
75494821
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
164 additions
and
103 deletions
+164
-103
openfire_i18n_en.properties
src/i18n/openfire_i18n_en.properties
+1
-3
IdentityStore.java
...ava/org/jivesoftware/openfire/keystore/IdentityStore.java
+38
-0
CertificateManager.java
src/java/org/jivesoftware/util/CertificateManager.java
+28
-0
import-keystore-certificate.jsp
src/web/import-keystore-certificate.jsp
+96
-100
security-keystore.jsp
src/web/security-keystore.jsp
+1
-0
No files found.
src/i18n/openfire_i18n_en.properties
View file @
5a52d003
...
...
@@ -3106,9 +3106,7 @@ mediaproxy.summary.stopbutton = Stop Active Sessions
# Import keystore certificate page
ssl.import.certificate.keystore.socket.title
=
Import Signed Certificate for Socket-based Communication
ssl.import.certificate.keystore.bosh.title
=
Import Signed Certificate for BOSH-based Communication
ssl.import.certificate.keystore.administrative.title
=
Import Signed Certificate for Administrative Purposes
ssl.import.certificate.keystore.title
=
Import Signed Certificate for Socket-based Communication
ssl.import.certificate.keystore.info
=
Use the form below to import a private key and certificate that was provided by a
\
Certificate Authority. Make sure that root certificates of the CA signing the certificate are present in the
\
truststore. Otherwise you will need to manually import them using the "keytool" command line tool. If you are
\
...
...
src/java/org/jivesoftware/openfire/keystore/IdentityStore.java
View file @
5a52d003
...
...
@@ -211,8 +211,46 @@ public class IdentityStore extends CertificateStore
/**
* Imports a certificate and the private key that was used to generate the certificate.
*
* This method will import the certificate and key in the store using a unique alias. This alias is returned.
*
* This method will fail when the provided certificate does not match the domain of this XMPP service.
*
* @param pemCertificates a PEM representation of the certificate or certificate chain (cannot be null or empty).
* @param pemPrivateKey a PEM representation of the private key (cannot be null or empty).
* @param passPhrase optional pass phrase (must be present if the private key is encrypted).
* @return The alias that was used (never null).
*/
public
String
installCertificate
(
String
pemCertificates
,
String
pemPrivateKey
,
String
passPhrase
)
throws
CertificateStoreConfigException
{
// Generate a unique alias.
final
String
domain
=
XMPPServer
.
getInstance
().
getServerInfo
().
getXMPPDomain
();
int
index
=
1
;
String
alias
=
domain
+
"_"
+
index
;
try
{
while
(
store
.
containsAlias
(
alias
)
)
{
index
=
index
+
1
;
alias
=
domain
+
"_"
+
index
;
}
}
catch
(
KeyStoreException
e
)
{
throw
new
CertificateStoreConfigException
(
"Unable to install a certificate into an identity store."
,
e
);
}
// Perform the installation using the generated alias.
installCertificate
(
alias
,
pemCertificates
,
pemPrivateKey
,
passPhrase
);
return
alias
;
}
/**
* Imports a certificate and the private key that was used to generate the certificate.
*
* This method will fail when the provided certificate does not match the domain of this XMPP service, or when the
* provided alias refers to an existing entry.
*
* @param alias the name (key) under which the certificate is to be stored in the store (cannot be null or empty).
* @param pemCertificates a PEM representation of the certificate or certificate chain (cannot be null or empty).
* @param pemPrivateKey a PEM representation of the private key (cannot be null or empty).
...
...
src/java/org/jivesoftware/util/CertificateManager.java
View file @
5a52d003
...
...
@@ -49,6 +49,7 @@ import org.bouncycastle.asn1.DEROutputStream;
import
org.bouncycastle.asn1.ASN1Sequence
;
import
org.bouncycastle.asn1.DERTaggedObject
;
import
org.bouncycastle.asn1.DERUTF8String
;
import
org.bouncycastle.asn1.pkcs.PrivateKeyInfo
;
import
org.bouncycastle.asn1.x509.GeneralName
;
import
org.bouncycastle.asn1.x509.GeneralNames
;
import
org.bouncycastle.asn1.x509.X509Extensions
;
...
...
@@ -59,7 +60,12 @@ import org.bouncycastle.openssl.PEMDecryptorProvider;
import
org.bouncycastle.openssl.PEMEncryptedKeyPair
;
import
org.bouncycastle.openssl.PEMKeyPair
;
import
org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter
;
import
org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder
;
import
org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder
;
import
org.bouncycastle.operator.InputDecryptorProvider
;
import
org.bouncycastle.operator.OperatorCreationException
;
import
org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo
;
import
org.bouncycastle.pkcs.PKCSException
;
import
org.bouncycastle.x509.X509V3CertificateGenerator
;
import
org.jivesoftware.openfire.keystore.CertificateStore
;
import
org.jivesoftware.openfire.keystore.CertificateStoreConfigException
;
...
...
@@ -659,6 +665,9 @@ public class CertificateManager {
if
(
pemRepresentation
==
null
||
pemRepresentation
.
trim
().
isEmpty
()
)
{
throw
new
IllegalArgumentException
(
"Argument 'pemRepresentation' cannot be null or an empty String."
);
}
if
(
passPhrase
==
null
)
{
passPhrase
=
""
;
}
try
(
Reader
reader
=
new
StringReader
(
pemRepresentation
.
trim
()
))
{
final
Object
object
=
new
PEMParser
(
reader
).
readObject
();
...
...
@@ -672,6 +681,25 @@ public class CertificateManager {
final
PEMDecryptorProvider
decProv
=
new
JcePEMDecryptorProviderBuilder
().
build
(
passPhrase
.
toCharArray
()
);
kp
=
converter
.
getKeyPair
(
(
(
PEMEncryptedKeyPair
)
object
).
decryptKeyPair
(
decProv
)
);
}
else
if
(
object
instanceof
PKCS8EncryptedPrivateKeyInfo
)
{
// Encrypted key - we will use provided password
try
{
final
PKCS8EncryptedPrivateKeyInfo
encryptedInfo
=
(
PKCS8EncryptedPrivateKeyInfo
)
object
;
final
InputDecryptorProvider
provider
=
new
JceOpenSSLPKCS8DecryptorProviderBuilder
().
build
(
passPhrase
.
toCharArray
()
);
final
PrivateKeyInfo
privateKeyInfo
=
encryptedInfo
.
decryptPrivateKeyInfo
(
provider
);
return
converter
.
getPrivateKey
(
privateKeyInfo
);
}
catch
(
PKCSException
|
OperatorCreationException
e
)
{
throw
new
IOException
(
"Unable to decrypt private key."
,
e
);
}
}
else
if
(
object
instanceof
PrivateKeyInfo
)
{
return
converter
.
getPrivateKey
(
(
PrivateKeyInfo
)
object
);
}
else
{
// Unencrypted key - no password needed
...
...
src/web/import-keystore-certificate.jsp
View file @
5a52d003
...
...
@@ -14,8 +14,8 @@
<%
webManager
.
init
(
request
,
response
,
session
,
application
,
out
);
%>
<%
// Get parameters:
final
boolean
save
=
ParamUtils
.
getParameter
(
request
,
"save"
)
!=
null
;
final
String
privateKey
=
ParamUtils
.
getParameter
(
request
,
"private
-k
ey"
);
final
boolean
save
=
ParamUtils
.
getParameter
(
request
,
"save"
)
!=
null
;
final
String
privateKey
=
ParamUtils
.
getParameter
(
request
,
"private
K
ey"
);
final
String
passPhrase
=
ParamUtils
.
getParameter
(
request
,
"passPhrase"
);
final
String
certificate
=
ParamUtils
.
getParameter
(
request
,
"certificate"
);
final
String
storePurposeText
=
ParamUtils
.
getParameter
(
request
,
"connectionType"
);
...
...
@@ -31,35 +31,24 @@
connectionType
=
null
;
}
pageContext
.
setAttribute
(
"connectionType"
,
connectionType
);
if
(
save
)
{
if
(
privateKey
==
null
||
""
.
equals
(
privateKey
)
)
{
if
(
privateKey
==
null
||
privateKey
.
trim
().
isEmpty
()
)
{
errors
.
put
(
"privateKey"
,
"privateKey"
);
}
if
(
certificate
==
null
||
""
.
equals
(
certificate
)
)
{
if
(
certificate
==
null
||
certificate
.
trim
().
isEmpty
()
)
{
errors
.
put
(
"certificate"
,
"certificate"
);
}
if
(
errors
.
isEmpty
())
{
try
{
final
IdentityStore
identityStore
=
XMPPServer
.
getInstance
().
getCertificateStoreManager
().
getIdentityStore
(
connectionType
);
// Create an alias for the signed certificate
String
domain
=
XMPPServer
.
getInstance
().
getServerInfo
().
getXMPPDomain
();
int
index
=
1
;
String
alias
=
domain
+
"_"
+
index
;
while
(
identityStore
.
getStore
().
containsAlias
(
alias
))
{
index
=
index
+
1
;
alias
=
domain
+
"_"
+
index
;
}
// Import certificate
identityStore
.
installCertificate
(
alias
,
privateKey
,
passPhrase
,
certificate
);
final
String
alias
=
identityStore
.
installCertificate
(
certificate
,
privateKey
,
passPhrase
);
// Log the event
webManager
.
logEvent
(
"imported SSL certificate in identity store "
+
storePurposeText
,
"alias = "
+
alias
);
webManager
.
logEvent
(
"imported SSL certificate in identity store "
+
connectionType
,
"alias = "
+
alias
);
response
.
sendRedirect
(
"security-keystore.jsp?connectionType="
+
storePurposeText
);
response
.
sendRedirect
(
"security-keystore.jsp?connectionType="
+
connectionType
+
"&addupdatesuccess=true"
);
return
;
}
catch
(
Exception
e
)
{
...
...
@@ -68,18 +57,20 @@
}
}
}
pageContext
.
setAttribute
(
"connectionType"
,
connectionType
);
pageContext
.
setAttribute
(
"errors"
,
errors
);
%>
<html>
<head>
<title><fmt:message
key=
"ssl.import.certificate.keystore.
${connectionType}.
title"
/></title>
<head>
<title><fmt:message
key=
"ssl.import.certificate.keystore.
box
title"
/></title>
<meta
name=
"pageID"
content=
"security-certificate-store-management"
/>
<meta
name=
"subPageID"
content=
"sidebar-certificate-store-${fn:toLowerCase(connectionType)}-identity-store"
/>
</head>
<body>
</head>
<body>
<%
pageContext
.
setAttribute
(
"errors"
,
errors
);
%>
<c:forEach
var=
"err"
items=
"
${
errors
}
"
>
<c:forEach
var=
"err"
items=
"
${
errors
}
"
>
<admin:infobox
type=
"error"
>
<c:choose>
<c:when
test=
"
${
err
.
key
eq
'privateKey'
}
"
>
...
...
@@ -105,54 +96,59 @@
</c:otherwise>
</c:choose>
</admin:infobox>
</c:forEach>
</c:forEach>
<p>
<p>
<fmt:message
key=
"ssl.import.certificate.keystore.info"
>
<fmt:param
value=
"<a href='http://java.sun.com/javase/downloads/index.jsp'>"
/>
<fmt:param
value=
"</a>"
/>
</fmt:message>
</p>
<!-- BEGIN 'Import Private Key and Certificate' -->
<form
action=
"import-keystore-certificate.jsp"
method=
"post"
name=
"f"
>
<input
type=
"hidden"
name=
"connectionType"
value=
"${connectionType}"
/>
<div
class=
"jive-contentBoxHeader"
>
<fmt:message
key=
"ssl.import.certificate.keystore.boxtitle"
/>
</div>
<div
class=
"jive-contentBox"
>
</p>
<!-- BEGIN 'Import Private Key and Certificate' -->
<form
action=
"import-keystore-certificate.jsp?connectionType=${connectionType}"
method=
"post"
>
<c:set
var=
"title"
>
Private Key
</c:set>
<admin:contentBox
title=
"
${
title
}
"
>
<p>
Please provide the PEM representation of the private key that should be used to identify Openfire.
</p>
<table
cellpadding=
"3"
cellspacing=
"0"
border=
"0"
>
<tbody>
<tr
valign=
"top"
>
<td
width=
"1%"
nowrap
class=
"c1"
>
<fmt:message
key=
"ssl.import.certificate.keystore.pass-phrase"
/
>
<label
for=
"passPhrase"
><fmt:message
key=
"ssl.import.certificate.keystore.pass-phrase"
/></label
>
</td>
<td
width=
"99%"
>
<input
type=
"text"
size=
"30"
maxlength=
"100"
name=
"passPhrase
"
>
<input
type=
"text"
size=
"60"
maxlength=
"200"
name=
"passPhrase"
id=
"passPhrase"
value=
"${not empty param.passPhrase ? param.passPhrase : ''}
"
>
</td>
</tr>
<tr
valign=
"top"
>
<td
width=
"1%"
nowrap
class=
"c1"
>
<fmt:message
key=
"ssl.import.certificate.keystore.private-key"
/
>
<label
for=
"privateKey"
><fmt:message
key=
"ssl.import.certificate.keystore.private-key"
/></label
>
</td>
<td
width=
"99%"
>
<textarea
name=
"private-key"
cols=
"60"
rows=
"5"
wrap=
"virtual"
></textarea>
<textarea
name=
"privateKey"
id=
"privateKey"
cols=
"80"
rows=
"15"
wrap=
"virtual"
><c:if
test=
"
${
not
empty
param
.
privateKey
}
"
><c:out
value=
"
${
param
.
privateKey
}
"
/></c:if
></textarea>
</td>
</tr>
</table>
</admin:contentBox>
<c:set
var=
"title"
>
Certificate
</c:set>
<admin:contentBox
title=
"
${
title
}
"
>
<p>
Please provide the PEM representation of the certificate chain that represents the identity of Openfire. Note that the certificate chain must be based on the private key provided above.
</p>
<table
cellpadding=
"3"
cellspacing=
"0"
border=
"0"
>
<tr
valign=
"top"
>
<td
width=
"1%"
nowrap
class=
"c1"
>
<fmt:message
key=
"ssl.import.certificate.keystore.certificate"
/
>
<label
for=
"certificate"
><fmt:message
key=
"ssl.import.certificate.keystore.certificate"
/></label
>
</td>
<td
width=
"99%"
>
<textarea
name=
"certificate"
cols=
"60"
rows=
"5"
wrap=
"virtual"
></textarea>
<textarea
name=
"certificate"
id=
"certificate"
cols=
"80"
rows=
"15"
wrap=
"virtual"
><c:if
test=
"
${
not
empty
param
.
certificate
}
"
><c:out
value=
"
${
param
.
certificate
}
"
/></c:if
></textarea>
</td>
</tr>
</tbody>
</table>
</div>
</admin:contentBox>
<input
type=
"submit"
name=
"save"
value=
"
<fmt:message
key=
"global.save"
/>
"
>
</form>
<!-- END 'Import Private Key and Certificate' -->
</form>
<!-- END 'Import Private Key and Certificate' -->
</body>
</body>
</html>
src/web/security-keystore.jsp
View file @
5a52d003
...
...
@@ -279,6 +279,7 @@
<c:forEach
items=
"
${
identities
}
"
var=
"currentItem"
varStatus=
"stat"
>
<c:out
value=
"
${
stat
.
first
?
''
:
','
}
${currentItem}"
/>
</c:forEach>
(
<c:out
value=
"
${
alias
}
"
/>
)
</a>
</td>
<td>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment