su3 parser

This commit is contained in:
Matt Drollette
2014-12-09 17:00:18 -06:00
parent aea04a6719
commit 2d445337c8
9 changed files with 408 additions and 70 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
/cert.pem
/key.pem
/netdb
i2pseeds.su3

View File

@ -3,6 +3,7 @@ package cmd
import (
"log"
// "github.com/MDrollette/go-i2p/reseed"
"github.com/codegangsta/cli"
)

40
cmd/verify.go Normal file
View File

@ -0,0 +1,40 @@
package cmd
import (
"fmt"
"os"
"github.com/MDrollette/go-i2p/su3"
"github.com/codegangsta/cli"
)
func NewSu3VerifyCommand() cli.Command {
return cli.Command{
Name: "verify",
Usage: "Verify a Su3 file",
Description: "Verify a Su3 file",
Action: su3VerifyAction,
Flags: []cli.Flag{},
}
}
func su3VerifyAction(c *cli.Context) {
file, err := os.Open(c.Args().Get(0))
if err != nil {
panic(err)
}
defer file.Close()
su3File := su3.Su3File{}
if err := su3.ReadSu3(file, &su3File); err != nil {
panic(err)
}
if err := su3File.VerifySignature(); nil != err {
panic(err)
}
fmt.Println(su3File.String())
fmt.Println("Verified signature.")
}

View File

@ -13,12 +13,9 @@ func main() {
app.Version = "0.1.0"
app.Usage = "I2P commands"
app.Flags = []cli.Flag{}
app.Before = func(c *cli.Context) error {
cmd.Init()
return nil
}
app.Commands = []cli.Command{
cmd.NewReseederCommand(),
cmd.NewSu3VerifyCommand(),
}
if err := app.Run(os.Args); err != nil {

View File

@ -1,19 +1,5 @@
package reseed
// read in all files from netdb dir into a slice of routerinfos
// for every unique requesting IP
// look up that IP in the db
// - if it exists, check the creation time
// - if the creation time is within the threshold, serve up the routerinfos
// - if the creation time is outside the threshold, or if it does not exist generate a new slice of routerinfos from the current master set
// at some regular interval, update the master slice with fresh netdb routerinfos
// can serve up html/ul of routerinfos
// can serve up su3 signed file
// https://geti2p.net/en/docs/spec/updates
import (
"bytes"
"fmt"

View File

@ -1,5 +1 @@
package reseed
const (
LIST_TEMPLATE = `<html><head><title>NetDB</title></head><body><ul>{{ range $index, $_ := . }}<li><a href="{{ $index }}">{{ $index }}</a></li>{{ end }}</ul></body></html>`
)

74
su3/crypto.go Normal file
View File

@ -0,0 +1,74 @@
package su3
import (
"crypto"
"crypto/dsa"
"crypto/ecdsa"
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"errors"
"math/big"
)
type dsaSignature struct {
R, S *big.Int
}
type ecdsaSignature dsaSignature
func checkSignature(c *x509.Certificate, algo x509.SignatureAlgorithm, signed, signature []byte) (err error) {
var hashType crypto.Hash
switch algo {
case x509.SHA1WithRSA, x509.DSAWithSHA1, x509.ECDSAWithSHA1:
hashType = crypto.SHA1
case x509.SHA256WithRSA, x509.DSAWithSHA256, x509.ECDSAWithSHA256:
hashType = crypto.SHA256
case x509.SHA384WithRSA, x509.ECDSAWithSHA384:
hashType = crypto.SHA384
case x509.SHA512WithRSA, x509.ECDSAWithSHA512:
hashType = crypto.SHA512
default:
return x509.ErrUnsupportedAlgorithm
}
if !hashType.Available() {
return x509.ErrUnsupportedAlgorithm
}
h := hashType.New()
h.Write(signed)
digest := h.Sum(nil)
switch pub := c.PublicKey.(type) {
case *rsa.PublicKey:
// the digest is already hashed, so we force a 0 here
return rsa.VerifyPKCS1v15(pub, 0, digest, signature)
case *dsa.PublicKey:
dsaSig := new(dsaSignature)
if _, err := asn1.Unmarshal(signature, dsaSig); err != nil {
return err
}
if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 {
return errors.New("x509: DSA signature contained zero or negative values")
}
if !dsa.Verify(pub, digest, dsaSig.R, dsaSig.S) {
return errors.New("x509: DSA verification failure")
}
return
case *ecdsa.PublicKey:
ecdsaSig := new(ecdsaSignature)
if _, err := asn1.Unmarshal(signature, ecdsaSig); err != nil {
return err
}
if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
return errors.New("x509: ECDSA signature contained zero or negative values")
}
if !ecdsa.Verify(pub, digest, ecdsaSig.R, ecdsaSig.S) {
return errors.New("x509: ECDSA verification failure")
}
return
}
return x509.ErrUnsupportedAlgorithm
}

119
su3/reseed_certs.go Normal file
View File

@ -0,0 +1,119 @@
package su3
import (
"crypto/x509"
"encoding/pem"
"fmt"
)
func certForSigner(signer string) (*x509.Certificate, error) {
var certString []byte
var ok bool
if certString, ok = reseedKeys[string(signer)]; !ok {
return nil, fmt.Errorf("Unknown signer '%s'", signer)
}
certPem, _ := pem.Decode(certString)
return x509.ParseCertificate(certPem.Bytes)
}
var (
reseedKeys = map[string][]byte{
"backup@mail.i2p": []byte(`-----BEGIN CERTIFICATE-----
MIIFfTCCA2WgAwIBAgIEOprmhjANBgkqhkiG9w0BAQ0FADBvMQswCQYDVQQGEwJY
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEYMBYGA1UEAwwPYmFja3VwQG1haWwu
aTJwMB4XDTEzMTAxMzEzNDQ1NVoXDTIzMTAxMzEzNDQ1NVowbzELMAkGA1UEBhMC
WFgxCzAJBgNVBAgTAlhYMQswCQYDVQQHEwJYWDEeMBwGA1UEChMVSTJQIEFub255
bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxGDAWBgNVBAMMD2JhY2t1cEBtYWls
LmkycDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIoAkobXwk/Enf1d
roHyqCyvcJfZJVTwb/LgYWAvCBMCr+RGqlSgtk3g69Y3I0xU08fD2kGt3r5Pwsbr
omXIbJAcccyLqmQ5QX6QgL+X9VpMDp9C4h2RogCrqLBAWw4cuZ4RS9VCpP1Yis7H
uejYqENP86p7BsRnuW/4cYnfunAdMpss4LpRGQXt1nTX+kfgCYgnKFbFqwAHt7yV
Ds+Pe6FuBHPlp+sc1amKRcUnSvhXLsv43VicnT7xYL/kUsN83wrtHA3B4aGDx3aA
3/EzuRmIXQB0BlTZILMEyYwG/nc4OsW82QYrvEZ9BIg9A4lF/wS/KZCICPxLF2zo
dGjnmlgkiA4s8eO+va/ElHyELjckVXqmG1eXHhSkEsDvOQJy01IUuwLinvq7cUbJ
HfJBZJllEg+sLDCv3FkEqN+XjBNFfQN4oNew4w6IPY6YH1INVB9LL0Cmdu4DudLv
TY8OcI8eSfez3hmm+pYQ23PJRYYnvRDnRECyIWBegkckWRh8U/WvZUYUvETK6EDl
/0KpTtfzX6MqHA5D6bTAB8Y3ijGMLrZ/B5vj5yCoZbLiGme9X2moR2k1LEhdhtzV
exsqezCpg6dn48FTX7mHjvR5/r4kz2jqBGmdPUWIIxnjFUzDUK3llVQiHihleHpe
jL4LqnhBGKWFRTaVwaIkBG4zAfIzAgMBAAGjITAfMB0GA1UdDgQWBBQNkfW7bSMl
1/4KDbgwrkf9x1Zu/TANBgkqhkiG9w0BAQ0FAAOCAgEAGg3a3rTf0EznQocmio0T
5gCoL0n8h6yKW/PyPAIELrd9wiYjhJFcWvMTcJJJnVqmAL5vpvhaAFVtAfx70MGa
0DZ7FvytK5hEfF4IqOFDyEEVGJR5rIpVK4MeI1nmwEsxdbW+FhODjtRzgYO8XBME
Xj4aY1FWg9vxc3reUj6PSFsZtsB0aLiRgL9JDovJIiRw0Uqr1v2wXBte5yVCxDge
vTREZtpK4cKetoOa68pwSXI32JwKE18j6bfdKVBCcYQKlKP/3gHGduaDrQv3w32S
DRym5s6MREeTUOtAw4wq46KpdOX8yyAqJPrCfMwS6ORd3t+egqOw0PUnsqb97w4O
lUtrRYvb2cOj60SmRx4vJvItyuHbKqIK7o2e1RcUZPXYoAVx2ww4XB2Wk4D7LSAs
cS7nLj8yAqzJ2qqtBzxu+zILJtkVa12dKF0xmS0BxBp4sCYiBtmAVE8AWQqEuSHA
FrMWqoXcjcfdvvyX487FFWWUE7ZBIn0hee2sK9J9+SPtqczJaN7TF3K3nzo65WJG
1epltmq2Ugjb67Gz7v4y7H23DJ/qhm8yLtCHTj69HTta5I08j6Kut924WLZaiMO/
4YoEL5AE63X0sxYibKFQiq7FW5nUJA280GRlY3xSMFzlB2ggazrUV3YAWVDhfdnI
flpzWXkFM2D36OUaubfe9YY=
-----END CERTIFICATE-----`),
"echelon@mail.i2p": []byte(`-----BEGIN CERTIFICATE-----
MIIFfzCCA2egAwIBAgIESg3kkzANBgkqhkiG9w0BAQ0FADBwMQswCQYDVQQGEwJY
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEZMBcGA1UEAwwQZWNoZWxvbkBtYWls
LmkycDAeFw0xNDA3MzExNjQ3MDJaFw0yNDA3MzAxNjQ3MDJaMHAxCzAJBgNVBAYT
AlhYMQswCQYDVQQIEwJYWDELMAkGA1UEBxMCWFgxHjAcBgNVBAoTFUkyUCBBbm9u
eW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRkwFwYDVQQDDBBlY2hlbG9uQG1h
aWwuaTJwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAmcEgLwwhzLNe
XLOMSrhwB8hWpOhfjo4s6S/wjBtjjUc8nI3D0hSn3HY26p0rvcvNEWexPUpPULmC
exGkU463nu7PiFONiORI1eJAiUFHibRiaA7Wboyo38pO73KirwjG07Y+Ua0jp+HS
+4FQ/I/9H/bPplReTOU/6hmRbgQ69U8nE68HzZHQxP68yVJ2rPHSXMPhF4R1h0G1
1mCAT+TgTsnwHNGF77XHJnY4/M4e2cgycEZjZow36C3t2mNDVkMgF19QQeb9WmLR
zREn3nq9BJqHpUkn9yWw0kKXTZSds+7UxESfzf3BzK0+hky2fh5H+qbYAo2lz4yj
81MXTAu+4RRkg4DBLlF+2dkclhwQLxxzvkRC6tPkn5i33Yltg7EfzA9IoQ05potJ
I+iOcF+aStfFgFj9u3B5UkcF4P0cH1QD3c6BK4hIezQYqRoPly1gHqg+XdwjG/dr
4as7HA9FTz3p2E8nClpIC1x3hfgwAdfd29aeBxO1WW/z99iMF7TBAF+u5T86XEW1
WpknqCbTli36yJ8a5fPWxZHrryBRJT5yLxejjFeadtutBSwljiVFq+Y38VqwFivq
VLiBt7IxAsZ8iilgfnnnAvBH6chWfSKb4H7kB4TJvDiV96QmmvoEaWYNHZozMhyK
tO3b5w+xqbJXyCLA3Q75jD0km76hjcECAwEAAaMhMB8wHQYDVR0OBBYEFAHQcAam
QRS/EUhuCSr9pB4Ux0rYMA0GCSqGSIb3DQEBDQUAA4ICAQBq1+1QLmgLAjrTg3tb
4XKgAVICQRoBDNUEobQg3pYeUX9eFNya2RxNljuvYpwT80ilGMPOXcjddmr5ngiK
dbGRcuuJk9MPEHtPaPT3+JJlvKQ3B3g2wva2Wz2OAyLZUGQs389K4nTbwh4QF0n2
aHFL8BHiD62hiKnCoNaW4ZovUNNvOxo9lMyAiaFU2gqQNcdad8hP9EAllbvbxDx9
Tjww2UbwQUIHS9rna4Tlu+f0hDXTWIutc2A51W2fJCb7L3+lYO7Wv55ND/WtryLZ
XpMp27+MpuEnN3kQmz/l9R0hIJsWc/x9GQkjm5wEaIZEyTtenqwRKGmVCtAj0Pgv
jn1L3/lWmrNq+OZHb/QeyfKtA3nXfQKVmT98ewQiK/S5i1xIAXCJPytOD887b/o1
cdurTmCiZMwgiQ+HLJqCg3MDa5mvKqRkRdZXfE6aQWEcSbpAhpV15R17q7L+Fg0W
shLSNucxyGNU8PjiC/nOmqfqUiPiMltJjPmscxBLim8foyxjakC4+6N6m+Jzgznj
PocBehFAfKYj66XEwzIBN7Z2uuXoYH9YptkocFjTzvchcryVulDWZ4FWxreUMhpM
4oyjjhSB4tB9clXlwMqg577q3D6Ms0zLTqsztyPN3zr6jGev3jpVq7Q1GOlciHPv
JNJOWTH/Vas1W6XlwGcOOAARTQ==
-----END CERTIFICATE-----`),
"meeh@mail.i2p": []byte(`-----BEGIN CERTIFICATE-----
MIIFeTCCA2GgAwIBAgIEZZozujANBgkqhkiG9w0BAQ0FADBtMQswCQYDVQQGEwJY
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEWMBQGA1UEAwwNbWVlaEBtYWlsLmky
cDAeFw0xNDA2MjgyMjQ5MDlaFw0yNDA2MjcyMjQ5MDlaMG0xCzAJBgNVBAYTAlhY
MQswCQYDVQQIEwJYWDELMAkGA1UEBxMCWFgxHjAcBgNVBAoTFUkyUCBBbm9ueW1v
dXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRYwFAYDVQQDDA1tZWVoQG1haWwuaTJw
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnVnmPE4uUvCky0yCnnVH
cJEDqzwDPupx0zr0YDlhZk5VOPPecx5haayJ/V6nXPc1aVVWn+CHfedcF2aBgN4K
5aBueS/l6l5WHcv02DofAqlTmyAws3oQeR1qoTuW24cKRtLR7h5bxv63f6bgp6e+
RihFNez6UxErnRPuJOJEO2Im6EgVp6fz7tQ7R35zxAUeES2YILPySvzy2vYm/EEG
jXX7Ap2A5svVo90xCMOeUZ/55vLsjyIshN+tV87U4xwvAkUmwsmWVHm3BQpHkI6z
zMJie6epB8Bqm0GYm0EcElJH4OCxGTvDLoghpswbuUO7iy3JSfoL7ZCnoiQdK9K4
yVVChj8lG+r7KaTowK96iZep+sZefjOt5VFGuW2Fi/WBv3ldiLlJAo/ZfrUM4+vG
fyNBXbl6bX87uTCGOT1p3dazo+zJMsAZ+Y93DlM/mDEWFa1kKNrs74syzaWEqF4L
KQE6VoYn80OOzafSigTVQgSwUtQtB0XGhMzJhyxU2XHWe1LFIy7Pta0B+lDiZj7c
I8nXxYjsDfEu/Elj/Ra9N6bH0awmgB5JDa+Tbir+oEM5SyDfpSaCGuatdGxjweGI
kVmFU0SqCZV/8TXbIu6MUVzTZMZVT94edifFSRad4fqw7eZbSXlPu++3d1/btn6h
ibM04nkv0mm+FxCKB/wdAkECAwEAAaMhMB8wHQYDVR0OBBYEFO7jIkSRkoXyJcho
9/Q0gDOINa5EMA0GCSqGSIb3DQEBDQUAA4ICAQBzfWO7+8HWOKLaYWToJ6XZbpNF
3wXv1yC4W/HRR80m4JSsq9r0d7838Nvd7vLVP6MY6MaVb/JnV76FdQ5WQ6ticD0Y
o3zmpqqbKVSspN0lrkig4surT88AjfVQz/vEIzKNQEbpzc3hC2LCiE2u+cK/ix4j
b9RohnaPvwLnew5RNQRpcmk+XejaNITISr2yQIwXL7TEYy8HdGCfzFSSFhKe9vkb
GsWS5ASrUzRoprswmlgRe8gEHI+d51Z7mWgna0/5mBz9bH/3QXtpxlLWm3bVV+kt
pZjQDTHE0GqG2YsD1Gmp4LU/JFhCojMTtiPCXmr9KFtpiVlx06DuKm5PC8Ak+5w+
m/DQYYfv9z+AA5Y430bjnzwg67bhqVyyek4wcDQinFswv3h4bIB7CJujDcEqXXza
lhG1ufPPCUTMrVjh7AShohZraqlSlyQPY9vEppLwD4W1d+MqDHM7ljOH7gQYaUPi
wE30AdXEOxLZcT3aRKxkKf2esNofSuUC/+NXQvPjpuI4UJKO3eegi+M9dbnKoNWs
MPPLPpycecWPheFYM5K6Ao63cjlUY2wYwCfDTFgjA5q8i/Rp7i6Z6fLE3YWJ4VdR
WOFB7hlluQ//jMW6M1qz6IYXmlUjcXl81VEvlOH/QBNrPvX3I3SYXYgVRnVGUudB
o3eNsanvTU+TIFBh2Q==
-----END CERTIFICATE-----`),
}
)

View File

@ -1,70 +1,194 @@
package su3
type Su3 struct {
// 0-5 Magic number "I2Psu3"
Magic [6]byte
import (
"archive/zip"
"bytes"
"crypto/x509"
"encoding/binary"
"fmt"
"os"
)
// 6 unused = 0
Unused1 [1]byte
const (
MAGIC_BYTES = "I2Psu3"
// 7 su3 file format version = 0
Format [1]byte
SIGTYPE_DSA = uint16(0)
SIGTYPE_ECDSA_SHA256 = uint16(1)
SIGTYPE_ECDSA_SHA384 = uint16(2)
SIGTYPE_ECDSA_SHA512 = uint16(3)
SIGTYPE_RSA_SHA256 = uint16(4)
SIGTYPE_RSA_SHA384 = uint16(5)
SIGTYPE_RSA_SHA512 = uint16(6)
// 8-9 Signature type
// 0x0000 = DSA-160
// 0x0001 = ECDSA-SHA256-P256
// 0x0002 = ECDSA-SHA384-P384
// 0x0003 = ECDSA-SHA512-P521
// 0x0004 = RSA-SHA256-2048
// 0x0005 = RSA-SHA384-3072
// 0x0006 = RSA-SHA512-4096
SignatureType [2]byte
CONTENT_TYPE_UNKNOWN = uint16(0)
CONTENT_TYPE_ROUTER = uint16(1)
CONTENT_TYPE_PLUGIN = uint16(2)
CONTENT_TYPE_RESEED = uint16(3)
CONTENT_TYPE_NEWS = uint16(4)
// 10-11 Signature length, e.g. 40 (0x0028) for DSA-160
SignatureLength [2]byte
FILE_TYPE_ZIP = uint8(0)
FILE_TYPE_XML = uint8(1)
FILE_TYPE_HTML = uint8(2)
FILE_TYPE_XMLGZ = uint8(3)
)
// 12 unused
Unused2 [1]byte
type Su3File struct {
Magic [6]byte
Format [1]byte
SignatureType uint16
SignatureLength uint16
VersionLength uint8
SignerIdLength uint8
ContentLength uint64
FileType [1]byte
ContentType [1]byte
// 13 Version length (in bytes not chars, including padding) must be at least 16 (0x10) for compatibility
VersionLength [1]byte
Version []byte
SignerId []byte
Content []byte
Signature []byte
SignedBytes []byte
}
// 14 unused
Unused3 [1]byte
func (s *Su3File) String() string {
var b bytes.Buffer
// 15 Signer ID length (in bytes not chars)
SignerIdLength [1]byte
// header
fmt.Fprintln(&b, "---------------------------")
// 16-23 Content length (not including header or sig)
ContentLength [8]byte
fmt.Fprintf(&b, "Magic: %s\n", s.Magic)
fmt.Fprintf(&b, "Format: %q\n", s.Format)
fmt.Fprintf(&b, "SignatureType: %q\n", s.SignatureType)
fmt.Fprintf(&b, "SignatureLength: %s\n", s.SignatureLength)
fmt.Fprintf(&b, "VersionLength: %s\n", s.VersionLength)
fmt.Fprintf(&b, "SignerIdLength: %s\n", s.SignerIdLength)
fmt.Fprintf(&b, "ContentLength: %s\n", s.ContentLength)
fmt.Fprintf(&b, "FileType: %q\n", s.FileType)
fmt.Fprintf(&b, "ContentType: %q\n", s.ContentType)
// 24 unused
Unused4 [1]byte
// content
fmt.Fprintln(&b, "---------------------------")
// 25 File type
// 0x00 = zip file
// 0x01 = xml file (as of 0.9.15)
// 0x02 = html file (as of 0.9.17)
// 0x03 = xml.gz file (as of 0.9.17)
FileType [1]byte
fmt.Fprintf(&b, "Version: %q\n", bytes.Trim(s.Version, "\x00"))
fmt.Fprintf(&b, "SignerId: %q\n", s.SignerId)
// fmt.Fprintf(&b, "Content: %q\n", s.Content)
// fmt.Fprintf(&b, "Signature: %q\n", s.Signature)
// 26 unused
Unused5 [1]byte
fmt.Fprintln(&b, "---------------------------")
// 27 Content type
// 0x00 = unknown
// 0x01 = router update
// 0x02 = plugin or plugin update
// 0x03 = reseed data
// 0x04 = news feed (as of 0.9.15)
ContentType [1]byte
return b.String()
}
// 28-39 unused
Unused6 [12]byte
func (s *Su3File) VerifySignature() error {
return verifySig(s.SignatureType, s.SignerId, s.Signature, s.SignedBytes)
}
func uzipData(c []byte) ([]byte, error) {
input := bytes.NewReader(c)
zipReader, err := zip.NewReader(input, int64(len(c)))
if nil != err {
return nil, err
}
var uncompressed []byte
for _, f := range zipReader.File {
rc, err := f.Open()
if err != nil {
panic(err)
}
uncompressed = append(uncompressed, []byte(f.Name+"\n")...)
rc.Close()
}
return uncompressed, nil
}
func verifySig(sigType uint16, signer, signature, signed []byte) (err error) {
var cert *x509.Certificate
if cert, err = certForSigner(string(signer)); nil != err {
return err
}
var sigAlg x509.SignatureAlgorithm
switch sigType {
case SIGTYPE_DSA:
sigAlg = x509.DSAWithSHA1
case SIGTYPE_ECDSA_SHA256:
sigAlg = x509.ECDSAWithSHA256
case SIGTYPE_ECDSA_SHA384:
sigAlg = x509.ECDSAWithSHA384
case SIGTYPE_ECDSA_SHA512:
sigAlg = x509.ECDSAWithSHA512
case SIGTYPE_RSA_SHA256:
sigAlg = x509.SHA256WithRSA
case SIGTYPE_RSA_SHA384:
sigAlg = x509.SHA384WithRSA
case SIGTYPE_RSA_SHA512:
sigAlg = x509.SHA512WithRSA
default:
return fmt.Errorf("Unsupported signature type.")
}
return checkSignature(cert, sigAlg, signed, signature)
}
func ReadSu3(file *os.File, su3File *Su3File) error {
var (
skip [1]byte
bigSkip [12]byte
)
// 0-5
binary.Read(file, binary.BigEndian, &su3File.Magic)
// 6
binary.Read(file, binary.BigEndian, &skip)
// 7
binary.Read(file, binary.BigEndian, &su3File.Format)
// 8-9
binary.Read(file, binary.BigEndian, &su3File.SignatureType)
// 10-11
binary.Read(file, binary.BigEndian, &su3File.SignatureLength)
// 12
binary.Read(file, binary.BigEndian, &skip)
// 13
binary.Read(file, binary.BigEndian, &su3File.VersionLength)
// 14
binary.Read(file, binary.BigEndian, &skip)
// 15
binary.Read(file, binary.BigEndian, &su3File.SignerIdLength)
// 16-23
binary.Read(file, binary.BigEndian, &su3File.ContentLength)
// 24
binary.Read(file, binary.BigEndian, &skip)
// 25
binary.Read(file, binary.BigEndian, &su3File.FileType)
// 26
binary.Read(file, binary.BigEndian, &skip)
// 27
binary.Read(file, binary.BigEndian, &su3File.ContentType)
// 28-39
binary.Read(file, binary.BigEndian, &bigSkip)
su3File.Version = make([]byte, su3File.VersionLength)
su3File.SignerId = make([]byte, su3File.SignerIdLength)
su3File.Content = make([]byte, su3File.ContentLength)
su3File.Signature = make([]byte, su3File.SignatureLength)
// 40-55+ Version, UTF-8 padded with trailing 0x00, 16 bytes minimum, length specified at byte 13. Do not append 0x00 bytes if the length is 16 or more.
binary.Read(file, binary.BigEndian, su3File.Version)
// xx+ ID of signer, (e.g. "zzz@mail.i2p") UTF-8, not padded, length specified at byte 15
binary.Read(file, binary.BigEndian, su3File.SignerId)
// xx+ Content, length and format specified in header
binary.Read(file, binary.BigEndian, su3File.Content)
// re-read from the beginning to get the signed content
signedEnd, _ := file.Seek(0, 1)
file.Seek(0, 0)
su3File.SignedBytes = make([]byte, signedEnd)
binary.Read(file, binary.BigEndian, su3File.SignedBytes)
// xx+ Signature, length specified in header, covers everything starting at byte 0
Version [16]byte
binary.Read(file, binary.BigEndian, su3File.Signature)
return nil
}