Changeset 4ffaf412


Ignore:
Timestamp:
Sep 13, 2013 1:02:37 PM (7 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
68aa1aea
Parents:
801ca47
Message:

SU3File:

  • enum for content type
  • fix NPE if private key not found
  • use certs instead of public keys for verification
  • improve validate-without-extract
  • new extract command
Location:
core/java/src/net/i2p/crypto
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • core/java/src/net/i2p/crypto/DirKeyRing.java

    r801ca47 r4ffaf412  
    77
    88import java.io.File;
     9import java.io.FileInputStream;
     10import java.io.InputStream;
    911import java.io.IOException;
    1012import java.security.GeneralSecurityException;
    1113import java.security.PublicKey;
     14import java.security.cert.CertificateFactory;
     15import java.security.cert.X509Certificate;
    1216
    1317import net.i2p.data.SigningPublicKey;
     
    2933    public SigningPublicKey getKey(String keyName, String scope, SigType type)
    3034                            throws GeneralSecurityException, IOException {
     35        keyName = keyName.replace("@", "_at_");
     36        File test = new File(keyName);
     37        if (test.getParent() != null)
     38            throw new IOException("bad key name");
    3139        File sd = new File(_base, scope);
    32         File td = new File(sd, Integer.toString(type.getCode()));
    33         File kd = new File(td, keyName + ".key");
     40        //File td = new File(sd, Integer.toString(type.getCode()));
     41        File kd = new File(sd, keyName + ".crt");
    3442        if (!kd.exists())
    3543            return null;
    36         PublicKey pk = SigUtil.importJavaPublicKey(kd, type);
    37         return SigUtil.fromJavaKey(pk, type);
     44        InputStream fis = null;
     45        try {
     46            fis = new FileInputStream(kd);
     47            CertificateFactory cf = CertificateFactory.getInstance("X.509");
     48            X509Certificate cert = (X509Certificate)cf.generateCertificate(fis);
     49            PublicKey pk = cert.getPublicKey();
     50            return SigUtil.fromJavaKey(pk, type);
     51        } finally {
     52            try { if (fis != null) fis.close(); } catch (IOException foo) {}
     53        }
    3854    }
    3955
  • core/java/src/net/i2p/crypto/KeyStoreUtil.java

    r801ca47 r4ffaf412  
    331331                buf.append('"').append(args[i]).append("\" ");
    332332            }
    333             error("Failed to create SSL keystore using command line: " + buf, null);
     333            error("Failed to generate keys using command line: " + buf, null);
    334334        }
    335335        return success;
  • core/java/src/net/i2p/crypto/SU3File.java

    r801ca47 r4ffaf412  
    4040
    4141    private final I2PAppContext _context;
    42     private final Map<SigningPublicKey, String> _trustedKeys;
    4342
    4443    private final File _file;
     
    4746    private String _signer;
    4847    private int _signerLength;
    49     private int _contentType;
     48    private ContentType _contentType;
    5049    private long _contentLength;
    5150    private SigningPublicKey _signerPubkey;
     
    6564    private static final int CONTENT_RESEED = 3;
    6665
     66    private enum ContentType {
     67        ROUTER(0, "update"),
     68        PLUGIN(1, "plugin"),
     69        RESEED(2, "reseed")
     70        ;
     71
     72        private final int code;
     73        private final String name;
     74
     75        ContentType(int code, String name) {
     76            this.code = code;
     77            this.name = name;
     78        }
     79        public int getCode() { return code; }
     80        public String getName() { return name; }
     81    }
     82
     83    private static final Map<Integer, ContentType> BY_CODE = new HashMap<Integer, ContentType>();
     84
     85    static {
     86        for (ContentType type : ContentType.values()) {
     87            BY_CODE.put(Integer.valueOf(type.getCode()), type);
     88        }
     89    }
     90
     91    /** @return null if not supported */
     92    public static ContentType getByCode(int code) {
     93        return BY_CODE.get(Integer.valueOf(code));
     94    }
    6795    private static final SigType DEFAULT_TYPE = SigType.DSA_SHA1;
    6896
    6997    /**
    70      *  Uses TrustedUpdate's default keys for verification.
     98     *
    7199     */
    72100    public SU3File(String file) {
     
    75103
    76104    /**
    77      *  Uses TrustedUpdate's default keys for verification.
     105     *
    78106     */
    79107    public SU3File(File file) {
    80         //this(file, (new TrustedUpdate()).getKeys());
    81         this(file, null);
    82     }
    83 
    84     /**
    85      *  @param trustedKeys map of pubkey to signer name, null ok if not verifying
    86      */
    87     public SU3File(File file, Map<SigningPublicKey, String> trustedKeys) {
    88         this(I2PAppContext.getGlobalContext(), file, trustedKeys);
    89     }
    90 
    91     /**
    92      *  @param trustedKeys map of pubkey to signer name, null ok if not verifying
    93      */
    94     public SU3File(I2PAppContext context, File file, Map<SigningPublicKey, String> trustedKeys) {
     108        this(I2PAppContext.getGlobalContext(), file);
     109    }
     110
     111    /**
     112     *
     113     */
     114    public SU3File(I2PAppContext context, File file) {
    95115        _context = context;
    96116        _file = file;
    97         _trustedKeys = trustedKeys;
    98117    }
    99118
     
    139158        if (foo != FILE_VERSION)
    140159            throw new IOException("bad file version");
    141         skip(in, 1);
    142         int sigTypeCode = in.read();
     160        int sigTypeCode = (int) DataHelper.readLong(in, 2);
    143161        _sigType = SigType.getByCode(sigTypeCode);
    144         // TODO, for other known algos we must start over with a new MessageDigest
    145         // (rewind 10 bytes)
     162        // In verifyAndMigrate it reads this far then rewinds, but we don't need to here
    146163        if (_sigType == null)
    147164            throw new IOException("unknown sig type: " + sigTypeCode);
     
    165182            throw new IOException("bad type");
    166183        skip(in, 1);
    167         _contentType = in.read();
    168         if (_contentType < CONTENT_ROUTER || _contentType > CONTENT_RESEED)
    169             throw new IOException("bad content type");
     184        int cType = in.read();
     185        _contentType = BY_CODE.get(Integer.valueOf(cType));
     186        if (_contentType == null)
     187            throw new IOException("unknown content type " + cType);
    170188        skip(in, 12);
    171189
     
    186204            throw new EOFException();
    187205        _signer = DataHelper.getUTF8(data);
    188         if (_trustedKeys != null) {
    189             for (Map.Entry<SigningPublicKey, String> e : _trustedKeys.entrySet()) {
    190                 if (e.getValue().equals(_signer)) {
    191                     _signerPubkey = e.getKey();
    192                     break;
    193                 }
    194             }
    195         } else {
    196             // testing
    197             KeyRing ring = new DirKeyRing(new File("su3keyring"));
    198             try {
    199                 _signerPubkey = ring.getKey(_signer, "default", _sigType);
    200             } catch (GeneralSecurityException gse) {
    201                 IOException ioe = new IOException("keystore error");
    202                 ioe.initCause(gse);
    203                 throw ioe;
    204             }
    205         }
     206
     207        KeyRing ring = new DirKeyRing(new File(_context.getBaseDir(), "certificates"));
     208        try {
     209            _signerPubkey = ring.getKey(_signer, _contentType.getName(), _sigType);
     210        } catch (GeneralSecurityException gse) {
     211            IOException ioe = new IOException("keystore error");
     212            ioe.initCause(gse);
     213            throw ioe;
     214        }
     215
    206216        if (_signerPubkey == null)
    207217            throw new IOException("unknown signer: " + _signer);
     
    223233
    224234    /**
     235     *  One-pass verify.
     236     *  Throws IOE on all format errors.
     237     *
     238     *  @return true if signature is good
     239     *  @since 0.9.9
     240     */
     241    public boolean verify() throws IOException {
     242        return verifyAndMigrate(null);
     243    }
     244
     245    /**
    225246     *  One-pass verify and extract the content.
    226247     *  Recommend extracting to a temp location as the sig is not checked until
     
    228249     *  Throws IOE on all format errors.
    229250     *
    230      *  @param migrateTo the output file, probably in zip format
     251     *  @param migrateTo the output file, probably in zip format. Null for verify only.
    231252     *  @return true if signature is good
    232253     */
     
    265286            if (_signerPubkey == null)
    266287                throw new IOException("unknown signer: " + _signer);
    267             out = new FileOutputStream(migrateTo);
     288            if (migrateTo != null)  // else verify only
     289                out = new FileOutputStream(migrateTo);
    268290            byte[] buf = new byte[16*1024];
    269291            long tot = 0;
     
    272294                if (read < 0)
    273295                    throw new EOFException();
    274                 out.write(buf, 0, read);
     296                if (migrateTo != null)  // else verify only
     297                    out.write(buf, 0, read);
    275298                tot += read;
    276299            }
     
    291314            if (in != null) try { in.close(); } catch (IOException ioe) {}
    292315            if (out != null) try { out.close(); } catch (IOException ioe) {}
    293             if (!rv)
     316            if (migrateTo != null && !rv)
    294317                migrateTo.delete();
    295318        }
     
    320343            out.write((byte) 0);
    321344            out.write((byte) FILE_VERSION);
    322             out.write((byte) 0);
    323             out.write((byte) sigType.getCode());
     345            DataHelper.writeLong(out, 2, sigType.getCode());
    324346            DataHelper.writeLong(out, 2, sigType.getSigLen());
    325347            out.write((byte) 0);
     
    402424            } else if ("keygen".equals(args[0])) {
    403425                if (args[1].equals("-t"))
    404                     ok = genKeysCLI(args[2], args[3], args[4]);
     426                    ok = genKeysCLI(args[2], args[3], args[4], args[5]);
    405427                else
    406                     ok = genKeysCLI(args[1], args[2]);
     428                    ok = genKeysCLI(args[1], args[2], args[3]);
     429            } else if ("extract".equals(args[0])) {
     430                ok = extractCLI(args[1], args[2]);
    407431            } else {
    408432                showUsageCLI();
     
    416440
    417441    private static final void showUsageCLI() {
    418         System.err.println("Usage: SU3File keygen       [-t type|code] publicKeyFile privateKeyFile");
     442        System.err.println("Usage: SU3File keygen       [-t type|code] publicKeyFile keystore.ks you@mail.i2p");
     443        System.err.println("       SU3File sign         [-c type|code] [-t type|code] inputFile.zip signedFile.su3 keystore.ks version you@mail.i2p");
    419444        System.err.println("       SU3File showversion  signedFile.su3");
    420         System.err.println("       SU3File sign         [-t type|code] inputFile.zip signedFile.su3 privateKeyFile version signerName@mail.i2p");
    421445        System.err.println("       SU3File verifysig    signedFile.su3");
    422         System.err.println(dumpSigTypes());
     446        System.err.println("       SU3File extract      signedFile.su3 outFile.zip");
     447        System.err.println(dumpTypes());
    423448    }
    424449
    425450    /** @since 0.9.9 */
    426     private static String dumpSigTypes() {
     451    private static String dumpTypes() {
    427452        StringBuilder buf = new StringBuilder(256);
    428453        buf.append("Available signature types:\n");
     
    430455            buf.append("      ").append(t).append("\t(code: ").append(t.getCode()).append(')');
    431456            if (t == SigType.DSA_SHA1)
     457                buf.append(" DEFAULT");
     458            buf.append('\n');
     459        }
     460        buf.append("Available content types:\n");
     461        for (ContentType t : EnumSet.allOf(ContentType.class)) {
     462            buf.append("      ").append(t).append("\t(code: ").append(t.getCode()).append(')');
     463            if (t == ContentType.ROUTER)
    432464                buf.append(" DEFAULT");
    433465            buf.append('\n');
     
    457489    private static final boolean showVersionCLI(String signedFile) {
    458490        try {
    459             SU3File file = new SU3File(new File(signedFile), null);
     491            SU3File file = new SU3File(signedFile);
    460492            String versionString = file.getVersionString();
    461493            if (versionString.equals(""))
     
    513545            File pkfile = new File(privateKeyFile);
    514546            PrivateKey pk = KeyStoreUtil.getPrivateKey(pkfile,KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD, signerName, keypw);
     547            if (pk == null) {
     548                System.out.println("Private key for " + signerName + " not found in keystore " + privateKeyFile);
     549                return false;
     550            }
    515551            SigningPrivateKey spk = SigUtil.fromJavaKey(pk, type);
    516552            SU3File file = new SU3File(signedFile);
     
    534570        try {
    535571            SU3File file = new SU3File(signedFile);
    536             //// fixme
    537             boolean isValidSignature = file.verifyAndMigrate(new File("/dev/null"));
     572            boolean isValidSignature = file.verify();
    538573            if (isValidSignature)
    539574                System.out.println("Signature VALID (signed by " + file.getSignerString() + ' ' + file._sigType + ')');
     
    552587     *  @since 0.9.9
    553588     */
    554     private static final boolean genKeysCLI(String publicKeyFile, String privateKeyFile) {
    555         return genKeysCLI(DEFAULT_TYPE, publicKeyFile, privateKeyFile);
     589    private static final boolean extractCLI(String signedFile, String outFile) {
     590        InputStream in = null;
     591        try {
     592            SU3File file = new SU3File(signedFile);
     593            File out = new File(outFile);
     594            boolean ok = file.verifyAndMigrate(out);
     595            if (ok)
     596                System.out.println("File extracted (signed by " + file.getSignerString() + ' ' + file._sigType + ')');
     597            else
     598                System.out.println("Signature INVALID (signed by " + file.getSignerString() + ' ' + file._sigType +')');
     599            return ok;
     600        } catch (IOException ioe) {
     601            System.out.println("Error extracting from file '" + signedFile + "'");
     602            ioe.printStackTrace();
     603            return false;
     604        }
    556605    }
    557606
     
    560609     *  @since 0.9.9
    561610     */
    562     private static final boolean genKeysCLI(String stype, String publicKeyFile, String privateKeyFile) {
     611    private static final boolean genKeysCLI(String publicKeyFile, String privateKeyFile, String alias) {
     612        return genKeysCLI(DEFAULT_TYPE, publicKeyFile, privateKeyFile, alias);
     613    }
     614
     615    /**
     616     *  @return success
     617     *  @since 0.9.9
     618     */
     619    private static final boolean genKeysCLI(String stype, String publicKeyFile, String privateKeyFile, String alias) {
    563620        SigType type = parseSigType(stype);
    564621        if (type == null) {
     
    566623            return false;
    567624        }
    568         return genKeysCLI(type, publicKeyFile, privateKeyFile);
     625        return genKeysCLI(type, publicKeyFile, privateKeyFile, alias);
    569626    }
    570627
     
    574631     *  @since 0.9.9
    575632     */
    576     private static final boolean genKeysCLI(SigType type, String publicKeyFile, String privateKeyFile) {
     633    private static final boolean genKeysCLI(SigType type, String publicKeyFile, String privateKeyFile, String alias) {
    577634        File pubFile = new File(publicKeyFile);
    578635        if (pubFile.exists()) {
     
    581638        }
    582639        File ksFile = new File(privateKeyFile);
    583         String alias = "";
    584640        String keypw = "";
    585641        try {
     
    604660        }
    605661        boolean success = KeyStoreUtil.createKeys(ksFile, KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD, alias,
    606                                                   "cn", "ou", 3652, type.getBaseAlgorithm().getName(),
     662                                                  alias, "I2P", 3652, type.getBaseAlgorithm().getName(),
    607663                                                  keylen, keypw);
    608664        if (!success) {
Note: See TracChangeset for help on using the changeset viewer.