/* SAAF: A static analyzer for APK files.
* Copyright (C) 2013 syssec.rub.de
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.rub.syssec.saaf.analysis.steps.metadata;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import de.rub.syssec.saaf.analysis.steps.hash.Hash;
import de.rub.syssec.saaf.model.application.Digest;
public class CertificateReader {
String file = "";
String fingerprint = null;
X509Certificate cert = null;
/**
* A reader, which reads the first Certificate out of a given apk File
* @param apkFile the apkFile
*/
public CertificateReader(File apkFile){
file=apkFile.getAbsolutePath();
}
/**
* A reader, which reads the first Certificate out of a given apk File
* @param apkFile the path to the apkFile
*/
public CertificateReader(String apkFile){
file=apkFile;
}
/**
*
* @return
*/
private boolean readFile() throws FileNotFoundException{
boolean s = true;
if(cert == null){
JarFile apk = null;
try {
if (!(new File(file).exists()))
throw new FileNotFoundException();
apk = new JarFile(file);
JarEntry entry = apk.getJarEntry("classes.dex");
InputStream is = apk.getInputStream(entry);
byte[] buffer = new byte[8192];
while (is.read(buffer, 0, buffer.length) != -1) {
// we just read. this will throw a SecurityException
// if a signature/digest check fails.
}
is.close();
//TODO: make more generic in case multiple certificates exist?
cert = (X509Certificate) entry.getCertificates()[0];
} catch (IOException e) {
e.printStackTrace();
s = false;
}
finally {
try { if (apk != null) apk.close(); } catch (Exception ignored) { }
}
}
return s;
}
/**
* This method calculates a SHA1 hash over the certificate, which equals openssl's fingerprint option
* @return The SHA1 Fingerprint of this Certificate, which is identical to openssl's "-fingerprint" option or null, in case it was not possible to generate a fingerprint
* @throws CertificateEncodingException
* @throws NoSuchAlgorithmException
* @throws IOException
*/
public String getSHA1() throws CertificateEncodingException, NoSuchAlgorithmException, FileNotFoundException, IOException{
if(readFile()){
byte[] encoded = cert.getEncoded();
String sha1 = Hash.calculateHash(Digest.SHA1, encoded);
return sha1;
}
return null;
}
/**
* Generates the MD5 Fingerprint of the read Certificate
* @return the MD5 Fingerprint or null, in case it was not possible to generate the md5 fingerprint
* @throws CertificateEncodingException
* @throws NoSuchAlgorithmException
* @throws IOException
*/
public String getMD5() throws CertificateEncodingException, NoSuchAlgorithmException, FileNotFoundException, IOException{
if(readFile()){
byte [] encoded=cert.getEncoded();
String sha1 = Hash.calculateHash(Digest.MD5, encoded);
return sha1;
}
return null;
}
/**
*
* @return the read X509Certificate or null, in case it was not possible to read the certificate
*/
public X509Certificate getCertificate(){
try {
readFile();
} catch (FileNotFoundException e) {
// FIXME: Log? Throw the exception?
e.printStackTrace();
}
return cert;
}
/**
* Get the Fingerprint of the Certificate read from the given apk File
* @return the fingerprint (SHA 1) or null, in case it was not possible to generate a fingerprint
* @throws IOException
* @throws FileNotFoundException If the path to the apk is wrong/File does not exist
* @throws NoSuchAlgorithmException
* @throws CertificateEncodingException
*/
public String getFingerprint() throws CertificateEncodingException, NoSuchAlgorithmException, FileNotFoundException, IOException{
if(fingerprint==null){
if(readFile()){
fingerprint = getSHA1();
return fingerprint;
}
return null;
}
return fingerprint;
}
}