Make AuthorizedKeysDecoder thread-safe
[netconf.git] / apps / callhome-provider / src / main / java / org / opendaylight / netconf / callhome / mount / AuthorizedKeysDecoder.java
index 6828c0ad8c430087ff8f9c9182e783f19b594e25..877992096756e5a12cc2966713080c076454935c 100644 (file)
@@ -35,10 +35,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-/**
- * FIXME: This should be probably located at AAA library.
- */
-public class AuthorizedKeysDecoder {
+final class AuthorizedKeysDecoder {
     private static final Logger LOG = LoggerFactory.getLogger(AuthorizedKeysDecoder.class);
 
     private static final ImmutableMap<String, String> ECDSA_CURVES = ImmutableMap.<String, String>builder()
@@ -73,23 +70,62 @@ public class AuthorizedKeysDecoder {
         }
     }
 
-    private byte[] bytes = new byte[0];
-    private int pos = 0;
+    private final byte[] bytes;
+    private int pos;
 
-    public PublicKey decodePublicKey(final SshPublicKey keyLine) throws GeneralSecurityException {
+    private AuthorizedKeysDecoder(final SshPublicKey keyLine) {
         bytes = keyLine.getValue();
-        pos = 0;
+    }
 
-        final var type = decodeType();
+    static @NonNull PublicKey decodePublicKey(final @NonNull SshPublicKey keyLine) throws GeneralSecurityException {
+        final var instance = new AuthorizedKeysDecoder(keyLine);
+        final var type = instance.decodeType();
         return switch (type) {
-            case KEY_TYPE_RSA -> decodeAsRSA();
-            case KEY_TYPE_DSA -> decodeAsDSA();
-            case KEY_TYPE_ECDSA -> decodeAsEcDSA();
-            default -> throw new IllegalArgumentException("Unknown decode key type " + type + " in " + keyLine);
+            case KEY_TYPE_RSA -> instance.decodeAsRSA();
+            case KEY_TYPE_DSA -> instance.decodeAsDSA();
+            case KEY_TYPE_ECDSA -> instance.decodeAsEcDSA();
+            default -> throw new NoSuchAlgorithmException("Unknown decode key type " + type + " in " + keyLine);
         };
     }
 
-    private PublicKey decodeAsEcDSA() throws GeneralSecurityException {
+    static @NonNull SshPublicKey encodePublicKey(final PublicKey publicKey) throws IOException {
+        final var baos = new ByteArrayOutputStream();
+
+        try (var dout = new DataOutputStream(baos)) {
+            if (publicKey instanceof RSAPublicKey rsa) {
+                dout.writeInt(KEY_TYPE_RSA_BYTES.length);
+                dout.write(KEY_TYPE_RSA_BYTES);
+                encodeBigInt(dout, rsa.getPublicExponent());
+                encodeBigInt(dout, rsa.getModulus());
+            } else if (publicKey instanceof DSAPublicKey dsa) {
+                final var dsaParams = dsa.getParams();
+                dout.writeInt(KEY_TYPE_DSA_BYTES.length);
+                dout.write(KEY_TYPE_DSA_BYTES);
+                encodeBigInt(dout, dsaParams.getP());
+                encodeBigInt(dout, dsaParams.getQ());
+                encodeBigInt(dout, dsaParams.getG());
+                encodeBigInt(dout, dsa.getY());
+            } else if (publicKey instanceof ECPublicKey ec) {
+                dout.writeInt(KEY_TYPE_ECDSA_BYTES.length);
+                dout.write(KEY_TYPE_ECDSA_BYTES);
+                dout.writeInt(ECDSA_SUPPORTED_CURVE_NAME_BYTES.length);
+                dout.write(ECDSA_SUPPORTED_CURVE_NAME_BYTES);
+
+                final var q = ec.getQ();
+                final var coordX = q.getAffineXCoord().getEncoded();
+                final var coordY = q.getAffineYCoord().getEncoded();
+                dout.writeInt(coordX.length + coordY.length + 1);
+                dout.writeByte(0x04);
+                dout.write(coordX);
+                dout.write(coordY);
+            } else {
+                throw new IOException("Unknown public key encoding: " + publicKey);
+            }
+        }
+        return new SshPublicKey(baos.toByteArray());
+    }
+
+    private @NonNull PublicKey decodeAsEcDSA() throws GeneralSecurityException {
         if (EC_FACTORY == null) {
             throw new NoSuchAlgorithmException("ECDSA keys are not supported");
         }
@@ -102,7 +138,7 @@ public class AuthorizedKeysDecoder {
         return EC_FACTORY.generatePublic(new ECPublicKeySpec(point, params256r1));
     }
 
-    private PublicKey decodeAsDSA() throws GeneralSecurityException {
+    private @NonNull PublicKey decodeAsDSA() throws GeneralSecurityException {
         if (DSA_FACTORY == null) {
             throw new NoSuchAlgorithmException("RSA keys are not supported");
         }
@@ -114,7 +150,7 @@ public class AuthorizedKeysDecoder {
         return DSA_FACTORY.generatePublic(new DSAPublicKeySpec(y, p, q, g));
     }
 
-    private PublicKey decodeAsRSA() throws GeneralSecurityException {
+    private @NonNull PublicKey decodeAsRSA() throws GeneralSecurityException {
         if (RSA_FACTORY == null) {
             throw new NoSuchAlgorithmException("RSA keys are not supported");
         }
@@ -149,41 +185,4 @@ public class AuthorizedKeysDecoder {
         out.writeInt(bytes.length);
         out.write(bytes);
     }
-
-    public static @NonNull SshPublicKey encodePublicKey(final PublicKey publicKey) throws IOException {
-        final var baos = new ByteArrayOutputStream();
-
-        try (var dout = new DataOutputStream(baos)) {
-            if (publicKey instanceof RSAPublicKey rsa) {
-                dout.writeInt(KEY_TYPE_RSA_BYTES.length);
-                dout.write(KEY_TYPE_RSA_BYTES);
-                encodeBigInt(dout, rsa.getPublicExponent());
-                encodeBigInt(dout, rsa.getModulus());
-            } else if (publicKey instanceof DSAPublicKey dsa) {
-                final var dsaParams = dsa.getParams();
-                dout.writeInt(KEY_TYPE_DSA_BYTES.length);
-                dout.write(KEY_TYPE_DSA_BYTES);
-                encodeBigInt(dout, dsaParams.getP());
-                encodeBigInt(dout, dsaParams.getQ());
-                encodeBigInt(dout, dsaParams.getG());
-                encodeBigInt(dout, dsa.getY());
-            } else if (publicKey instanceof ECPublicKey ec) {
-                dout.writeInt(KEY_TYPE_ECDSA_BYTES.length);
-                dout.write(KEY_TYPE_ECDSA_BYTES);
-                dout.writeInt(ECDSA_SUPPORTED_CURVE_NAME_BYTES.length);
-                dout.write(ECDSA_SUPPORTED_CURVE_NAME_BYTES);
-
-                final var q = ec.getQ();
-                final var coordX = q.getAffineXCoord().getEncoded();
-                final var coordY = q.getAffineYCoord().getEncoded();
-                dout.writeInt(coordX.length + coordY.length + 1);
-                dout.writeByte(0x04);
-                dout.write(coordX);
-                dout.write(coordY);
-            } else {
-                throw new IOException("Unknown public key encoding: " + publicKey);
-            }
-        }
-        return new SshPublicKey(baos.toByteArray());
-    }
 }