aboutsummaryrefslogblamecommitdiff
path: root/verify_signature.go
blob: 2b2b16b29da61aa3a8fdccf2fe774acaef9c5216 (plain) (tree)
1
2
3
4
5
6
7
8
9
10

            

                                                  





                 
                   


          
      


             
           




                                                
                                                         

                                                                          




                                                                 








                                                                                   






















                                                                                                     



                                                                             
                                         


                                                                                
                                     
                      
                             










                                                                                               



                                                                                                                       























                                                                          



























                                                                         
                                   

                                        
 

                                                                      
                         
                                                     


                                   







                                                               
package main

// verify a signature generated with a private key

import (
  "crypto/ecdsa"
  "crypto/sha256"
  "crypto/x509"
  "encoding/asn1"
  "encoding/pem"
  "encoding/base64"
  "errors"
  "flag"
  "fmt"
  "io"
  "io/ioutil"
  "math/big"
  "os"
  "strings"
)

type (
  VerifySignatureFlags struct {
    Message        string // the message to sign
    MessageStream  string // the path to the input stream
    PublicKeyPath  string // path to the private key
    Signature      string // a path or stream to output the private key to
    SignatureStream string // read signature from an input stream
    Format         string // the format of the signature

    message_stream   io.Reader // the message stream
    signature_stream io.Reader // the signature stream
  }
  // 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()
  if flags.SignatureStream == flags.MessageStream &&
     ( flags.Message == "" && flags.Signature == "") {
    crash_with_help(2, "Signature and Message stream can't be the same source!")
  }

  // open streams
  if flags.Message == "" && flags.MessageStream != "" {
    message_stream, err := open_input_stream(flags.MessageStream)
    if err != nil {
      crash_with_help(2, fmt.Sprintf("Error when opening stream %s: %s", flags.MessageStream, err))
    }
    defer message_stream.Close()
    flags.message_stream = message_stream
  }
  if flags.Signature == "" && flags.SignatureStream != "" {
    signature_stream, err := open_input_stream(flags.SignatureStream)
    if err != nil {
      crash_with_help(2, fmt.Sprintf("Error when opening stream %s: %s", flags.SignatureStream, err))
    }
    defer signature_stream.Close()
    flags.signature_stream = signature_stream
  }

  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)
  if err != nil {
    crash_with_help(2, fmt.Sprintf("Error when loading the signature: %s", err))
  }
  message, err := load_message(flags)
  hash := sha256.New()
  hash.Write([]byte(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.SignatureStream, "signature-stream", "", "the path to the stream of the signature (file, STDIN)")
  fs.StringVar(&flags.Format, "format", "auto", "the input format of the signature (auto, binary, base64)")
  fs.StringVar(&flags.Message, "message", "", "the message to validate")
  fs.StringVar(&flags.MessageStream, "message-stream", "STDIN", "the path to the stream to validate (file, STDIN)")
  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(flags VerifySignatureFlags) (*Signature, error) {
  var signature_raw []byte
  var err error
  if flags.Message != "" {
    signature_raw = []byte(flags.Message)
  } else {
    signature_raw, err = ioutil.ReadAll(flags.signature_stream)
    if err != nil { return nil, err }
  }

  switch strings.ToLower(flags.Format) {
  case "auto":
    sig, err := load_signature_base64(signature_raw)
    if err != nil {
      sig, err = load_signature_binary(signature_raw)
      if err != nil { return nil, err }
      return sig, nil
    }
    return sig, nil
  case "base64": return load_signature_base64(signature_raw)
  case "binary": return load_signature_binary(signature_raw)
  default: return nil, errors.New("Unknown format!")
  }
}

// convert the signature from base64 into a signature
func load_signature_base64(signature_raw []byte) (*Signature, error) {
  asn1_sig, err := base64.StdEncoding.DecodeString(string(signature_raw))
  if err != nil { return nil, err }
  return load_signature_binary(asn1_sig)
}

// convert the signature from asn1 into a signature
func load_signature_binary(signature_raw []byte) (*Signature, error) {
  var signature Signature
  _, err := asn1.Unmarshal(signature_raw, &signature)
  if err != nil { return nil, err }
  return &signature, nil
}

// load the message from a stream or the parameter
func load_message(flags VerifySignatureFlags) (string, error) {
  if flags.Message != "" { return flags.Message, nil }
  message, err := ioutil.ReadAll(flags.message_stream)
  if err != nil { return "", err }
  return string(message), nil
}