package main
import (
"crypto/ecdsa"
"crypto/sha256"
"crypto/x509"
"encoding/asn1"
"encoding/pem"
"errors"
"flag"
"fmt"
"io/ioutil"
"math/big"
"os"
)
type (
VerifySignatureFlags struct {
Message string // the message to sign
PublicKeyPath string // path to the private key
Signature string // a path or stream to output the private key to
}
// struct to load the signature into (which is basically two bigint in byte form)
Signature struct {
R, S *big.Int
}
)
func verify_signature() {
flags := parse_verify_signature_flags()
public_key, err := load_public_key_ecdsa(flags.PublicKeyPath)
if err != nil {
crash_with_help(2, fmt.Sprintf("Error when loading public key: %s", err))
}
signature, err := load_signature(flags.Signature)
if err != nil {
crash_with_help(2, fmt.Sprintf("Error when loading the signature: %s", err))
}
hash := sha256.New()
hash.Write([]byte(flags.Message))
success := ecdsa.Verify(public_key, hash.Sum(nil), signature.R, signature.S)
fmt.Println(success)
}
// parse the parameters
func parse_verify_signature_flags() VerifySignatureFlags {
flags := VerifySignatureFlags{}
fs := flag.NewFlagSet("verify-signature", flag.ExitOnError)
fs.StringVar(&flags.PublicKeyPath, "public-key", "", "path to the public key file")
fs.StringVar(&flags.Signature, "signature", "", "path where the signature file can be found")
fs.StringVar(&flags.Message, "message", "", "the message to be validated")
fs.Parse(os.Args[2:])
return flags
}
// load the private key from pem file
func load_public_key_ecdsa(path string) (*ecdsa.PublicKey, error) {
public_key_file, err := os.Open(path)
if err != nil { return nil, err }
public_key_pem, err := ioutil.ReadAll(public_key_file)
if err != nil { return nil, err }
public_key_file.Close()
block, _ := pem.Decode(public_key_pem)
if block.Type != TypeLabelPubKey {
return nil, errors.New(fmt.Sprintf("No public key found in %s", path))
}
public_key, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil { return nil, err }
return public_key.(*ecdsa.PublicKey), nil
}
// parse the signature from asn1 file
func load_signature(path string) (*Signature, error) {
signature_file, err := os.Open(path)
if err != nil { return nil, err }
signature_raw, err := ioutil.ReadAll(signature_file)
if err != nil { return nil, err }
signature_file.Close()
var signature Signature
_, err = asn1.Unmarshal(signature_raw, &signature)
if err != nil { return nil, err }
return &signature, nil
}