/*
* Copyright (c) 2013, Psiphon Inc.
* All rights reserved.
*
* 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 ca.psiphon.ploggy;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* Representation of Ploggy public Identity.
*
* Users exchange public identities, each of which contains an X509 certificate for
* authentication and a Hidden Service public key for routing. The identity also contains
* the user's selected nickname. All of the identity parameters are bound together with a
* digital signature which can be verified using the X509 certificate.
*/
public class Identity {
private static final String LOG_TAG = "Identity";
// TODO: distinct root cert and server/client (transport) certs?
public static class PublicIdentity {
public final String mNickname;
public final String mX509Certificate;
public final String mHiddenServiceHostname;
// Note: we're using certs in TLS for client authentication. The Tor HS auth cookie
// is used for its anti-DoS properties: only clients that have your identity can
// initiate a connection to your hidden service. This value doesn't need to remain
// secret, but DoS protection is enhanced when identity exchange is confidential.
public final String mHiddenServiceAuthCookie;
public final String mSignature;
public PublicIdentity(
String nickname,
String x509Certificate,
String hiddenServiceHostname,
String hiddenServicAuthCookie,
String signature) {
mNickname = nickname;
mX509Certificate = x509Certificate;
mHiddenServiceHostname = hiddenServiceHostname;
mHiddenServiceAuthCookie = hiddenServicAuthCookie;
mSignature = signature;
}
public byte[] getFingerprint() throws Utils.ApplicationError {
// Note: Fingerprint excludes hidden service auth cookies, since those may change.
// (Those values *are* included in signatures to ensure a false value isn't swapped in, denying service.)
return X509.getFingerprint(mNickname, mX509Certificate, mHiddenServiceHostname);
}
}
public static class PrivateIdentity {
public final String mX509PrivateKey;
public final String mHiddenServicePrivateKey;
public PrivateIdentity(String x509PrivateKey, String hiddenServicePrivateKey) {
mX509PrivateKey = x509PrivateKey;
mHiddenServicePrivateKey = hiddenServicePrivateKey;
}
}
private static byte[] getPublicSigningData(
String nickname,
String rootCertificate,
String hiddenServiceHostname,
String hiddenServiceAuthCookie) throws Utils.ApplicationError {
try {
ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
byteArray.write(nickname.getBytes("UTF-8"));
byteArray.write(rootCertificate.getBytes("UTF-8"));
byteArray.write(hiddenServiceHostname.getBytes("UTF-8"));
byteArray.write(hiddenServiceAuthCookie.getBytes("UTF-8"));
return byteArray.toByteArray();
} catch (IOException e) {
throw new Utils.ApplicationError(LOG_TAG, e);
}
}
public static PublicIdentity makeSignedPublicIdentity(
String nickname,
X509.KeyMaterial x509KeyMaterial,
HiddenService.KeyMaterial hiddenServiceKeyMaterial) throws Utils.ApplicationError {
String signature = X509.sign(
x509KeyMaterial,
getPublicSigningData(
nickname,
x509KeyMaterial.mCertificate,
hiddenServiceKeyMaterial.mHostname,
hiddenServiceKeyMaterial.mAuthCookie));
return new PublicIdentity(
nickname,
x509KeyMaterial.mCertificate,
hiddenServiceKeyMaterial.mHostname,
hiddenServiceKeyMaterial.mAuthCookie,
signature);
}
public static boolean verifyPublicIdentity(PublicIdentity publicIdentity) {
// TODO: implement
return false;
}
public static PrivateIdentity makePrivateIdentity(X509.KeyMaterial x509KeyMaterial, HiddenService.KeyMaterial hiddenServiceKeyMaterial) {
return new PrivateIdentity(
x509KeyMaterial.mPrivateKey,
hiddenServiceKeyMaterial.mPrivateKey);
}
}