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
}
|