2 * Copyright (C) 2014 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 package org
.strongswan
.android
.security
;
19 import java
.io
.FileInputStream
;
20 import java
.io
.FileNotFoundException
;
21 import java
.io
.FileOutputStream
;
22 import java
.io
.IOException
;
23 import java
.security
.MessageDigest
;
24 import java
.security
.NoSuchAlgorithmException
;
25 import java
.security
.cert
.Certificate
;
26 import java
.security
.cert
.CertificateEncodingException
;
27 import java
.security
.cert
.CertificateException
;
28 import java
.security
.cert
.CertificateFactory
;
29 import java
.security
.cert
.X509Certificate
;
30 import java
.util
.ArrayList
;
31 import java
.util
.Date
;
32 import java
.util
.regex
.Pattern
;
34 import org
.strongswan
.android
.logic
.StrongSwanApplication
;
35 import org
.strongswan
.android
.utils
.Utils
;
37 import android
.content
.Context
;
39 public class LocalCertificateStore
41 private static final String FILE_PREFIX
= "certificate-";
42 private static final String ALIAS_PREFIX
= "local:";
43 private static final Pattern ALIAS_PATTERN
= Pattern
.compile("^" + ALIAS_PREFIX
+ "[0-9a-f]{40}$");
46 * Add the given certificate to the store
47 * @param cert the certificate to add
48 * @return true if successful
50 public boolean addCertificate(Certificate cert
)
52 if (!(cert
instanceof X509Certificate
))
53 { /* only accept X.509 certificates */
56 String keyid
= getKeyId(cert
);
64 /* we replace any existing file with the same alias */
65 out
= StrongSwanApplication
.getContext().openFileOutput(FILE_PREFIX
+ keyid
, Context
.MODE_PRIVATE
);
68 out
.write(cert
.getEncoded());
71 catch (CertificateEncodingException e
)
91 catch (FileNotFoundException e
)
99 * Delete the certificate with the given alias
100 * @param alias a certificate's alias
102 public void deleteCertificate(String alias
)
104 if (ALIAS_PATTERN
.matcher(alias
).matches())
106 alias
= alias
.substring(ALIAS_PREFIX
.length());
107 StrongSwanApplication
.getContext().deleteFile(FILE_PREFIX
+ alias
);
112 * Retrieve the certificate with the given alias
113 * @param alias a certificate's alias
114 * @return certificate object or null
116 public X509Certificate
getCertificate(String alias
)
118 if (!ALIAS_PATTERN
.matcher(alias
).matches())
122 alias
= alias
.substring(ALIAS_PREFIX
.length());
125 FileInputStream in
= StrongSwanApplication
.getContext().openFileInput(FILE_PREFIX
+ alias
);
128 CertificateFactory factory
= CertificateFactory
.getInstance("X.509");
129 X509Certificate certificate
= (X509Certificate
)factory
.generateCertificate(in
);
132 catch (CertificateException e
)
142 catch (IOException e
)
148 catch (FileNotFoundException e
)
156 * Returns the creation date of the certificate with the given alias
157 * @param alias certificate alias
158 * @return creation date or null if not found
160 public Date
getCreationDate(String alias
)
162 if (!ALIAS_PATTERN
.matcher(alias
).matches())
166 alias
= alias
.substring(ALIAS_PREFIX
.length());
167 File file
= StrongSwanApplication
.getContext().getFileStreamPath(FILE_PREFIX
+ alias
);
168 return file
.exists() ?
new Date(file
.lastModified()) : null;
172 * Returns a list of all known certificate aliases
173 * @return list of aliases
175 public ArrayList
<String
> aliases()
177 ArrayList
<String
> list
= new ArrayList
<String
>();
178 for (String file
: StrongSwanApplication
.getContext().fileList())
180 if (file
.startsWith(FILE_PREFIX
))
182 list
.add(ALIAS_PREFIX
+ file
.substring(FILE_PREFIX
.length()));
189 * Check if the store contains a certificate with the given alias
190 * @param alias certificate alias
191 * @return true if the store contains the certificate
193 public boolean containsAlias(String alias
)
195 return getCreationDate(alias
) != null;
199 * Returns a certificate alias based on a SHA-1 hash of the public key.
201 * @param cert certificate to get an alias for
202 * @return hex encoded alias, or null if failed
204 public String
getCertificateAlias(Certificate cert
)
206 String keyid
= getKeyId(cert
);
207 return keyid
!= null ? ALIAS_PREFIX
+ keyid
: null;
211 * Calculates the SHA-1 hash of the public key of the given certificate.
212 * @param cert certificate to get the key ID from
213 * @return hex encoded SHA-1 hash of the public key or null if failed
215 private String
getKeyId(Certificate cert
)
220 md
= java
.security
.MessageDigest
.getInstance("SHA1");
221 byte[] hash
= md
.digest(cert
.getPublicKey().getEncoded());
222 return Utils
.bytesToHex(hash
);
224 catch (NoSuchAlgorithmException e
)