This repository has been archived by the owner on Feb 10, 2021. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement JCA-based SHA1-RSA signature verification logic
To be used for Travis's new authentication mechanism Refs #43
- Loading branch information
Showing
5 changed files
with
96 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package com.getbootstrap.savage.crypto | ||
|
||
import scala.util.{Try,Success,Failure} | ||
import java.io.StringReader | ||
import java.security.spec.X509EncodedKeySpec | ||
import org.bouncycastle.util.io.pem.PemReader | ||
import org.bouncycastle.util.io.pem.PemObject | ||
|
||
|
||
sealed class MalformedPemException(cause: Throwable) extends RuntimeException("The given data did not conform to the PEM format!", cause) | ||
|
||
sealed class UnexpectedPemDataTypeException(expectedType: String, pemObj: PemObject) | ||
extends RuntimeException(s"PEM contained data of unexpected type! Expected: ${expectedType} Actual: ${pemObj.getType}") | ||
|
||
// PEM is the name for the format that involves "-----BEGIN PUBLIC KEY-----" etc. | ||
object Pem { | ||
private val PublicKeyPemType = "PUBLIC KEY" | ||
|
||
@throws[MalformedPemException]("if there is a problem decoding the PEM data") | ||
private def decode(pem: String): PemObject = { | ||
val pemReader = new PemReader(new StringReader(pem)) | ||
val pemObjTry = Try { pemReader.readPemObject() } | ||
val closeTry = Try { pemReader.close() } | ||
(pemObjTry, closeTry) match { | ||
case (Failure(readExc), _) => throw new MalformedPemException(readExc) | ||
case (_, Failure(closeExc)) => throw new MalformedPemException(closeExc) | ||
case (Success(pemObj), Success(_)) => pemObj | ||
} | ||
} | ||
|
||
// Decodes PKCS8 data in PEM format into a X509EncodedKeySpec | ||
// which can be handled by sun.security.rsa.RSAKeyFactory | ||
@throws[UnexpectedPemDataTypeException]("if the PEM contains non-public-key data") | ||
def decodePublicKeyIntoSpec(publicKeyInPem: String): X509EncodedKeySpec = { | ||
val pemObj = decode(publicKeyInPem) | ||
pemObj.getType match { | ||
case PublicKeyPemType => new X509EncodedKeySpec(pemObj.getContent) | ||
case unexpectedType => throw new UnexpectedPemDataTypeException(PublicKeyPemType, pemObj) | ||
} | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
src/main/scala/com/getbootstrap/savage/crypto/RsaPublicKey.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.getbootstrap.savage.crypto | ||
|
||
import scala.util.Try | ||
import java.security.KeyFactory | ||
import java.security.PublicKey | ||
import java.security.spec.X509EncodedKeySpec | ||
|
||
|
||
sealed case class RsaPublicKey private(publicKey: PublicKey) | ||
|
||
object RsaPublicKey { | ||
private val rsaKeyFactory = KeyFactory.getInstance("RSA") // Supported in all spec-compliant JVMs | ||
|
||
def fromX509Spec(keySpec: X509EncodedKeySpec): Try[RsaPublicKey] = Try{ rsaKeyFactory.generatePublic(keySpec) }.map{ new RsaPublicKey(_) } | ||
def fromPem(pem: String): Try[RsaPublicKey] = Try{ Pem.decodePublicKeyIntoSpec(pem) }.flatMap{ fromX509Spec(_) } | ||
} |
27 changes: 27 additions & 0 deletions
27
src/main/scala/com/getbootstrap/savage/crypto/Sha1WithRsa.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.getbootstrap.savage.crypto | ||
|
||
import java.security.Signature | ||
import java.security.SignatureException | ||
import java.security.InvalidKeyException | ||
|
||
|
||
object Sha1WithRsa { | ||
private val signatureAlgorithmName = "SHA1withRSA" // Supported in all spec-compliant JVMs | ||
private def newSignatureVerifier(): Signature = Signature.getInstance(signatureAlgorithmName) | ||
|
||
def verifySignature(signature: Array[Byte], publicKey: RsaPublicKey, signedData: Array[Byte]): SignatureVerificationStatus = { | ||
val verifier = newSignatureVerifier() | ||
try { | ||
verifier.initVerify(publicKey.publicKey) | ||
verifier.update(signedData) | ||
verifier.verify(signature) match { | ||
case true => SuccessfullyVerified | ||
case false => FailedVerification | ||
} | ||
} | ||
catch { | ||
case keyExc:InvalidKeyException => ExceptionDuringVerification(keyExc) | ||
case sigExc:SignatureException => ExceptionDuringVerification(sigExc) | ||
} | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
src/main/scala/com/getbootstrap/savage/crypto/SignatureVerificationStatus.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.getbootstrap.savage.crypto | ||
|
||
sealed trait SignatureVerificationStatus | ||
|
||
object SuccessfullyVerified extends SignatureVerificationStatus | ||
|
||
trait FailedVerification extends SignatureVerificationStatus | ||
object FailedVerification extends SignatureVerificationStatus | ||
case class ExceptionDuringVerification(error: Throwable) extends FailedVerification |