forked from I2P_Developers/i2p.i2p
Family: Publish pubkey in RI; use it to verify if no cert available
This commit is contained in:
@ -188,24 +188,29 @@ public class StatisticsManager {
|
|||||||
if (family != null) {
|
if (family != null) {
|
||||||
stats.setProperty(FamilyKeyCrypto.OPT_NAME, family);
|
stats.setProperty(FamilyKeyCrypto.OPT_NAME, family);
|
||||||
String sig = null;
|
String sig = null;
|
||||||
|
String key = null;
|
||||||
RouterInfo oldRI = _context.router().getRouterInfo();
|
RouterInfo oldRI = _context.router().getRouterInfo();
|
||||||
if (oldRI != null) {
|
if (oldRI != null) {
|
||||||
// don't do it if family changed
|
// don't do it if family changed
|
||||||
if (family.equals(oldRI.getOption(FamilyKeyCrypto.OPT_NAME))) {
|
if (family.equals(oldRI.getOption(FamilyKeyCrypto.OPT_NAME))) {
|
||||||
// copy over the signature
|
// copy over the pubkey and signature
|
||||||
|
key = oldRI.getOption(FamilyKeyCrypto.OPT_KEY);
|
||||||
|
if (key != null)
|
||||||
|
stats.setProperty(FamilyKeyCrypto.OPT_KEY, key);
|
||||||
sig = oldRI.getOption(FamilyKeyCrypto.OPT_SIG);
|
sig = oldRI.getOption(FamilyKeyCrypto.OPT_SIG);
|
||||||
if (sig != null)
|
if (sig != null)
|
||||||
stats.setProperty(FamilyKeyCrypto.OPT_SIG, sig);
|
stats.setProperty(FamilyKeyCrypto.OPT_SIG, sig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sig == null) {
|
if (sig == null || key == null) {
|
||||||
FamilyKeyCrypto fkc = _context.router().getFamilyKeyCrypto();
|
FamilyKeyCrypto fkc = _context.router().getFamilyKeyCrypto();
|
||||||
if (fkc != null) {
|
if (fkc != null) {
|
||||||
try {
|
try {
|
||||||
sig = fkc.sign(family, h);
|
stats.putAll(fkc.sign(family, h));
|
||||||
stats.setProperty(FamilyKeyCrypto.OPT_SIG, sig);
|
|
||||||
} catch (GeneralSecurityException gse) {
|
} catch (GeneralSecurityException gse) {
|
||||||
_log.error("Failed to sign router family", gse);
|
_log.error("Failed to sign router family", gse);
|
||||||
|
stats.remove(FamilyKeyCrypto.OPT_KEY);
|
||||||
|
stats.remove(FamilyKeyCrypto.OPT_SIG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ public class FamilyKeyCrypto {
|
|||||||
private static final String KEYSTORE_PREFIX = "family-";
|
private static final String KEYSTORE_PREFIX = "family-";
|
||||||
private static final String KEYSTORE_SUFFIX = ".ks";
|
private static final String KEYSTORE_SUFFIX = ".ks";
|
||||||
private static final int DEFAULT_KEY_VALID_DAYS = 3652; // 10 years
|
private static final int DEFAULT_KEY_VALID_DAYS = 3652; // 10 years
|
||||||
// Note that we can't use RSA here, as the b64 sig would exceed the 256 char limit for a Mapping
|
// Note that we can't use RSA here, as the b64 sig would exceed the 255 char limit for a Mapping
|
||||||
// Note that we can't use EdDSA here, as keystore doesn't know how, and encoding/decoding is unimplemented
|
// Note that we can't use EdDSA here, as keystore doesn't know how, and encoding/decoding is unimplemented
|
||||||
private static final String DEFAULT_KEY_ALGORITHM = SigType.ECDSA_SHA256_P256.isAvailable() ? "EC" : "DSA";
|
private static final String DEFAULT_KEY_ALGORITHM = SigType.ECDSA_SHA256_P256.isAvailable() ? "EC" : "DSA";
|
||||||
private static final int DEFAULT_KEY_SIZE = SigType.ECDSA_SHA256_P256.isAvailable() ? 256 : 1024;
|
private static final int DEFAULT_KEY_SIZE = SigType.ECDSA_SHA256_P256.isAvailable() ? 256 : 1024;
|
||||||
@ -62,6 +62,7 @@ public class FamilyKeyCrypto {
|
|||||||
private static final String CERT_DIR = "certificates/family";
|
private static final String CERT_DIR = "certificates/family";
|
||||||
public static final String OPT_NAME = "family";
|
public static final String OPT_NAME = "family";
|
||||||
public static final String OPT_SIG = "family.sig";
|
public static final String OPT_SIG = "family.sig";
|
||||||
|
public static final String OPT_KEY = "family.key";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -109,16 +110,20 @@ public class FamilyKeyCrypto {
|
|||||||
*
|
*
|
||||||
* @param family non-null, must match that we were initialized with or will throw GSE
|
* @param family non-null, must match that we were initialized with or will throw GSE
|
||||||
* @param h non-null
|
* @param h non-null
|
||||||
* @return non-null base 64 signature string to be added to the RI
|
* @return non-null options to be added to the RI
|
||||||
* @throws GeneralSecurityException on null hash, null or changed family, or signing error
|
* @throws GeneralSecurityException on null hash, null or changed family, or signing error
|
||||||
*/
|
*/
|
||||||
public String sign(String family, Hash h) throws GeneralSecurityException {
|
public Map<String, String> sign(String family, Hash h) throws GeneralSecurityException {
|
||||||
if (_privkey == null)
|
if (_privkey == null) {
|
||||||
throw new GeneralSecurityException("family name set, must restart router");
|
_log.logAlways(Log.WARN, "family name now set, must restart router to generate or load keys");
|
||||||
|
throw new GeneralSecurityException("family name now set, must restart router to generate or load keys");
|
||||||
|
}
|
||||||
if (h == null)
|
if (h == null)
|
||||||
throw new GeneralSecurityException("null router hash");
|
throw new GeneralSecurityException("null router hash");
|
||||||
if (!_fname.equals(family))
|
if (!_fname.equals(family)) {
|
||||||
throw new GeneralSecurityException("family name changed, must restart router");
|
_log.logAlways(Log.WARN, "family name changed, must restart router to generate or load new keys");
|
||||||
|
throw new GeneralSecurityException("family name changed, must restart router to generate or load new keys");
|
||||||
|
}
|
||||||
byte[] nb = DataHelper.getUTF8(_fname);
|
byte[] nb = DataHelper.getUTF8(_fname);
|
||||||
int len = nb.length + Hash.HASH_LENGTH;
|
int len = nb.length + Hash.HASH_LENGTH;
|
||||||
byte[] b = new byte[len];
|
byte[] b = new byte[len];
|
||||||
@ -127,7 +132,11 @@ public class FamilyKeyCrypto {
|
|||||||
Signature sig = _context.dsa().sign(b, _privkey);
|
Signature sig = _context.dsa().sign(b, _privkey);
|
||||||
if (sig == null)
|
if (sig == null)
|
||||||
throw new GeneralSecurityException("sig failed");
|
throw new GeneralSecurityException("sig failed");
|
||||||
return sig.toBase64();
|
Map<String, String> rv = new HashMap<String, String>(3);
|
||||||
|
rv.put(OPT_NAME, family);
|
||||||
|
rv.put(OPT_KEY, _pubkey.getType().getCode() + ";" + _pubkey.toBase64());
|
||||||
|
rv.put(OPT_SIG, sig.toBase64());
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -161,13 +170,47 @@ public class FamilyKeyCrypto {
|
|||||||
if (_negativeCache.contains(h))
|
if (_negativeCache.contains(h))
|
||||||
return false;
|
return false;
|
||||||
spk = loadCert(name);
|
spk = loadCert(name);
|
||||||
|
if (spk == null) {
|
||||||
|
// look for a b64 key in the RI
|
||||||
|
String skey = ri.getOption(OPT_KEY);
|
||||||
|
if (skey != null) {
|
||||||
|
int semi = skey.indexOf(";");
|
||||||
|
if (semi > 0) {
|
||||||
|
try {
|
||||||
|
int code = Integer.parseInt(skey.substring(0, semi));
|
||||||
|
SigType type = SigType.getByCode(code);
|
||||||
|
if (type != null) {
|
||||||
|
byte[] bkey = Base64.decode(skey.substring(semi + 1));
|
||||||
|
if (bkey != null) {
|
||||||
|
spk = new SigningPublicKey(type, bkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
if (_log.shouldInfo())
|
||||||
|
_log.info("Bad b64 family key: " + ri, e);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
if (_log.shouldInfo())
|
||||||
|
_log.info("Bad b64 family key: " + ri, e);
|
||||||
|
} catch (ArrayIndexOutOfBoundsException e) {
|
||||||
|
if (_log.shouldInfo())
|
||||||
|
_log.info("Bad b64 family key: " + ri, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (spk == null) {
|
if (spk == null) {
|
||||||
_negativeCache.add(h);
|
_negativeCache.add(h);
|
||||||
if (_log.shouldInfo())
|
if (_log.shouldInfo())
|
||||||
_log.info("No cert for " + h + ' ' + name);
|
_log.info("No cert or valid key for " + h + ' ' + name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (!spk.getType().isAvailable()) {
|
||||||
|
_negativeCache.add(h);
|
||||||
|
if (_log.shouldInfo())
|
||||||
|
_log.info("Unsupported crypto for sig for " + h);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
byte[] bsig = Base64.decode(ssig);
|
byte[] bsig = Base64.decode(ssig);
|
||||||
if (bsig == null) {
|
if (bsig == null) {
|
||||||
_negativeCache.add(h);
|
_negativeCache.add(h);
|
||||||
|
Reference in New Issue
Block a user