aboutsummaryrefslogtreecommitdiff
path: root/verify_signature.go
blob: b661e9a3c538c073c7be45f5982959c484777e42 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package main

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
}