|
1 | 1 | package com.advancedtelematic.tuf.cli.repo
|
2 | 2 |
|
3 |
| -import java.nio.file.attribute.{PosixFilePermission, PosixFilePermissions} |
4 |
| -import java.nio.file.{FileAlreadyExistsException, Files, Path} |
5 |
| -import PosixFilePermission._ |
6 |
| -import scala.collection.JavaConverters._ |
7 |
| -import com.advancedtelematic.libtuf.data.TufDataType.{KeyType, TufKey, TufKeyPair, TufPrivateKey} |
| 3 | +import com.advancedtelematic.libtuf.data.TufCodecs._ |
| 4 | +import com.advancedtelematic.libtuf.data.TufDataType.{EcPrime256KeyType, Ed25519KeyType, KeyType, RsaKeyType, TufKey, TufKeyPair, TufPrivateKey} |
8 | 5 | import com.advancedtelematic.tuf.cli.DataType.KeyName
|
| 6 | +import io.circe.jawn._ |
| 7 | +import io.circe.syntax._ |
| 8 | +import net.i2p.crypto.eddsa.Utils |
| 9 | +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo |
| 10 | +import org.bouncycastle.openssl.{PEMKeyPair, PEMParser} |
9 | 11 | import org.slf4j.LoggerFactory
|
10 | 12 |
|
11 |
| -import scala.util.Try |
12 |
| -import com.advancedtelematic.libtuf.data.TufCodecs._ |
13 |
| -import io.circe.syntax._ |
14 |
| -import io.circe.jawn._ |
| 13 | +import java.io.StringReader |
| 14 | +import java.nio.file.attribute.PosixFilePermission._ |
| 15 | +import java.nio.file.attribute.{PosixFilePermission, PosixFilePermissions} |
| 16 | +import java.nio.file.{FileAlreadyExistsException, Files, Path} |
| 17 | +import scala.collection.JavaConverters._ |
| 18 | +import scala.util.{Failure, Success, Try} |
15 | 19 |
|
16 | 20 |
|
17 | 21 | object CliKeyStorage {
|
@@ -65,7 +69,7 @@ class CliKeyStorage private (root: Path) {
|
65 | 69 | for {
|
66 | 70 | _ <- ensureKeysDirCreated()
|
67 | 71 | _ <- writePublic(name, pub)
|
68 |
| - _ = log.info(s"Saved public key to ${root.relativize(name.publicKeyPath)}}") |
| 72 | + _ = log.info(s"Saved public key to ${root.relativize(name.publicKeyPath)}") |
69 | 73 | } yield ()
|
70 | 74 | }
|
71 | 75 |
|
@@ -95,4 +99,54 @@ class CliKeyStorage private (root: Path) {
|
95 | 99 | pub <- readPublicKey(keyName)
|
96 | 100 | priv <- readPrivateKey(keyName)
|
97 | 101 | } yield (pub, priv)
|
| 102 | + |
| 103 | + def importPublicKey(pemPath: Path, keyNames: List[KeyName]): Try[Unit] = { |
| 104 | + import cats.instances.list._ |
| 105 | + import cats.instances.try_._ |
| 106 | + import cats.syntax.traverse._ |
| 107 | + |
| 108 | + for { |
| 109 | + key <- readPublicKeyPem(pemPath) |
| 110 | + _ <- keyNames.traverse(keyName => writePublicKey(keyName, key)) |
| 111 | + } yield () |
| 112 | + } |
| 113 | + |
| 114 | + private def readPublicKeyPem(path: Path): Try[TufKey] = { |
| 115 | + val tryReadPemFile = Try { |
| 116 | + val source = scala.io.Source.fromFile(path.toFile) |
| 117 | + val pem = source.mkString |
| 118 | + source.close() |
| 119 | + pem |
| 120 | + } |
| 121 | + |
| 122 | + val pemToPublicKeyInfo = (pem: String) => Try { |
| 123 | + val parser = new PEMParser(new StringReader(pem)) |
| 124 | + parser.readObject() match { |
| 125 | + case key: SubjectPublicKeyInfo => key |
| 126 | + case keyPair: PEMKeyPair => keyPair.getPublicKeyInfo |
| 127 | + } |
| 128 | + } |
| 129 | + |
| 130 | + val tryParseRSA = (pem: String) => |
| 131 | + RsaKeyType.crypto.parsePublic(pem) |
| 132 | + |
| 133 | + val tryParseEcPrime256 = (pem: String) => |
| 134 | + pemToPublicKeyInfo(pem) |
| 135 | + .map(k => Utils.bytesToHex(k.getEncoded)) |
| 136 | + .flatMap(EcPrime256KeyType.crypto.parsePublic) |
| 137 | + |
| 138 | + val tryParseEd25519 = (pem: String) => |
| 139 | + pemToPublicKeyInfo(pem) |
| 140 | + .map(k => Utils.bytesToHex(k.getPublicKeyData.getBytes)) |
| 141 | + .flatMap(Ed25519KeyType.crypto.parsePublic) |
| 142 | + |
| 143 | + val publicKeyTry = (pem: String) => |
| 144 | + tryParseRSA(pem).orElse(tryParseEcPrime256(pem)).orElse(tryParseEd25519(pem)) |
| 145 | + .transform(key => Success(key), _ => Failure(new Exception(s"Cannot parse public key from $path"))) |
| 146 | + |
| 147 | + for { |
| 148 | + pem <- tryReadPemFile |
| 149 | + publicKey <- publicKeyTry(pem) |
| 150 | + } yield publicKey |
| 151 | + } |
98 | 152 | }
|
0 commit comments