refactor su3 readers to support signature verification
This commit is contained in:
249
lib/su3/su3.go
249
lib/su3/su3.go
@@ -1,40 +1,43 @@
|
||||
// Package su3 implements reading the SU3 file format.
|
||||
//
|
||||
// SU3 files provide content that is signed by a known identity.
|
||||
// They are used to distributed many types of data, including reseed files,
|
||||
// They are used to distribute many types of data, including reseed files,
|
||||
// plugins, blocklists, and more.
|
||||
//
|
||||
// See: https://geti2p.net/spec/updates#su3-file-specification
|
||||
//
|
||||
// The Read() function takes an io.Reader, and it returns four values:
|
||||
// - meta: The SU3 file metadata, describing the type of file and the identity that signed it.
|
||||
// - content: An io.Reader of the file contents.
|
||||
// - signature: An io.Reader of the signature.
|
||||
// - err: An error if something went wrong.
|
||||
// The Read() function takes an io.Reader, and it returns a *SU3. The *SU3 contains
|
||||
// the SU3 file metadata, such as the type of the content and the signer ID.
|
||||
// In order to get the file contents, one must pass in the public key associated
|
||||
// with the file's signer, so that the signature can be validated. The content
|
||||
// can still be read without passing in the key, but after returning the full
|
||||
// content the error ErrInvalidSignature will be returned.
|
||||
//
|
||||
// Example usage:
|
||||
// // Let's say we are reading an SU3 file from an HTTP body.
|
||||
// meta, content, signature, err := su3.Read(body)
|
||||
// // Let's say we are reading an SU3 file from an HTTP body, which is an io.Reader.
|
||||
// su3File, err := su3.Read(body)
|
||||
// if err != nil {
|
||||
// // Handle error.
|
||||
// }
|
||||
// bytes, err := ioutil.ReadAll(content)
|
||||
// // Look up this signer's key.
|
||||
// key := somehow_lookup_the_key(su3File.SignerID)
|
||||
// // Read the content.
|
||||
// contentReader := su3File.Content(key)
|
||||
// bytes, err := ioutil.ReadAll(contentReader)
|
||||
// if errors.Is(err, su3.ErrInvalidSignature) {
|
||||
// // The signature is invalid.
|
||||
// // The signature is invalid, OR a nil key was provided.
|
||||
// } else if err != nil {
|
||||
// // Handle error.
|
||||
// }
|
||||
//
|
||||
// If you want to parse from a []byte, you can wrap them like this:
|
||||
// meta, content, signature, err := su3.Read(bytes.NewReader([]byte{0x00, 0x01, 0x02, 0x03}))
|
||||
// mySU3FileBytes := []byte{0x00, 0x01, 0x02, 0x03}
|
||||
// su3File, err := su3.Read(bytes.NewReader(mySU3FileBytes))
|
||||
//
|
||||
// Note: the content io.Reader must be read *before* the signature io.Reader.
|
||||
// If you read the signature first, the content bytes will be thrown away.
|
||||
// If you then attempt to read the content, you will get an error.
|
||||
// For clarification, see TestReadSignatureFirst.
|
||||
//
|
||||
// PLEASE NOTE: Signature validation is not implemented at this time.
|
||||
// Use with caution.
|
||||
// Note: if you want to read the content, the Content() io.Reader must be read
|
||||
// *before* the Signature() io.Reader. If you read the signature first, the
|
||||
// content bytes will be thrown away. If you then attempt to read the content,
|
||||
// you will get an error. For clarification, see TestReadSignatureFirst.
|
||||
package su3
|
||||
|
||||
import (
|
||||
@@ -136,7 +139,7 @@ var ErrInvalidSignature = errors.New("invalid signature")
|
||||
|
||||
const magicBytes = "I2Psu3"
|
||||
|
||||
type SU3Meta struct {
|
||||
type SU3 struct {
|
||||
SignatureType SignatureType
|
||||
SignatureLength uint16
|
||||
ContentLength uint64
|
||||
@@ -144,114 +147,132 @@ type SU3Meta struct {
|
||||
ContentType ContentType
|
||||
Version string
|
||||
SignerID string
|
||||
mut sync.Mutex
|
||||
reader io.Reader
|
||||
bytesRead uint64
|
||||
publicKey interface{}
|
||||
contentReader *su3Reader
|
||||
signatureReader *su3Reader
|
||||
}
|
||||
|
||||
func Read(reader io.Reader) (meta *SU3Meta, content io.Reader, signature io.Reader, err error) {
|
||||
func (su3 *SU3) Content(publicKey interface{}) io.Reader {
|
||||
su3.publicKey = publicKey
|
||||
return su3.contentReader
|
||||
}
|
||||
|
||||
func (su3 *SU3) Signature() io.Reader {
|
||||
return su3.signatureReader
|
||||
}
|
||||
|
||||
func Read(reader io.Reader) (su3 *SU3, err error) {
|
||||
// Magic bytes.
|
||||
mbytes := make([]byte, len(magicBytes))
|
||||
l, err := reader.Read(mbytes)
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, nil, fmt.Errorf("reading magic bytes: %w", err)
|
||||
return nil, fmt.Errorf("reading magic bytes: %w", err)
|
||||
}
|
||||
if l != len(mbytes) {
|
||||
return nil, nil, nil, ErrMissingMagicBytes
|
||||
return nil, ErrMissingMagicBytes
|
||||
}
|
||||
if string(mbytes) != magicBytes {
|
||||
return nil, nil, nil, ErrMissingMagicBytes
|
||||
return nil, ErrMissingMagicBytes
|
||||
}
|
||||
|
||||
// Unused byte 6.
|
||||
unused := [1]byte{}
|
||||
l, err = reader.Read(unused[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, nil, fmt.Errorf("reading unused byte 6: %w", err)
|
||||
return nil, fmt.Errorf("reading unused byte 6: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
return nil, nil, nil, ErrMissingUnusedByte6
|
||||
return nil, ErrMissingUnusedByte6
|
||||
}
|
||||
|
||||
// SU3 file format version (always 0).
|
||||
l, err = reader.Read(unused[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, nil, fmt.Errorf("reading SU3 file format version: %w", err)
|
||||
return nil, fmt.Errorf("reading SU3 file format version: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
return nil, nil, nil, ErrMissingFileFormatVersion
|
||||
return nil, ErrMissingFileFormatVersion
|
||||
}
|
||||
if unused[0] != 0x00 {
|
||||
return nil, nil, nil, ErrMissingFileFormatVersion
|
||||
return nil, ErrMissingFileFormatVersion
|
||||
}
|
||||
|
||||
meta = &SU3Meta{}
|
||||
su3 = &SU3{
|
||||
mut: sync.Mutex{},
|
||||
reader: reader,
|
||||
}
|
||||
|
||||
// Signature type.
|
||||
sigTypeBytes := [2]byte{}
|
||||
l, err = reader.Read(sigTypeBytes[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, nil, fmt.Errorf("reading signature type: %w", err)
|
||||
return nil, fmt.Errorf("reading signature type: %w", err)
|
||||
}
|
||||
if l != 2 {
|
||||
return nil, nil, nil, ErrMissingSignatureType
|
||||
return nil, ErrMissingSignatureType
|
||||
}
|
||||
sigType, ok := sigTypes[sigTypeBytes]
|
||||
if !ok {
|
||||
return nil, nil, nil, ErrMissingSignatureType
|
||||
return nil, ErrMissingSignatureType
|
||||
}
|
||||
meta.SignatureType = sigType
|
||||
su3.SignatureType = sigType
|
||||
|
||||
// Signature length.
|
||||
sigLengthBytes := [2]byte{}
|
||||
l, err = reader.Read(sigLengthBytes[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, nil, fmt.Errorf("reading signature length: %w", err)
|
||||
return nil, fmt.Errorf("reading signature length: %w", err)
|
||||
}
|
||||
if l != 2 {
|
||||
return nil, nil, nil, ErrMissingSignatureLength
|
||||
return nil, ErrMissingSignatureLength
|
||||
}
|
||||
sigLen := binary.BigEndian.Uint16(sigLengthBytes[:])
|
||||
// TODO check that sigLen is the correct length for sigType.
|
||||
meta.SignatureLength = sigLen
|
||||
su3.SignatureLength = sigLen
|
||||
|
||||
// Unused byte 12.
|
||||
l, err = reader.Read(unused[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, nil, fmt.Errorf("reading unused byte 12: %w", err)
|
||||
return nil, fmt.Errorf("reading unused byte 12: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
return nil, nil, nil, ErrMissingUnusedByte12
|
||||
return nil, ErrMissingUnusedByte12
|
||||
}
|
||||
|
||||
// Version length.
|
||||
verLengthBytes := [1]byte{}
|
||||
l, err = reader.Read(verLengthBytes[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, nil, fmt.Errorf("reading version length: %w", err)
|
||||
return nil, fmt.Errorf("reading version length: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
return nil, nil, nil, ErrMissingVersionLength
|
||||
return nil, ErrMissingVersionLength
|
||||
}
|
||||
verLen := binary.BigEndian.Uint16([]byte{0x00, verLengthBytes[0]})
|
||||
if verLen < 16 {
|
||||
return nil, nil, nil, ErrVersionTooShort
|
||||
return nil, ErrVersionTooShort
|
||||
}
|
||||
|
||||
// Unused byte 14.
|
||||
l, err = reader.Read(unused[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, nil, fmt.Errorf("reading unused byte 14: %w", err)
|
||||
return nil, fmt.Errorf("reading unused byte 14: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
return nil, nil, nil, ErrMissingUnusedByte14
|
||||
return nil, ErrMissingUnusedByte14
|
||||
}
|
||||
|
||||
// Signer ID length.
|
||||
sigIDLengthBytes := [1]byte{}
|
||||
l, err = reader.Read(sigIDLengthBytes[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, nil, fmt.Errorf("reading signer id length: %w", err)
|
||||
return nil, fmt.Errorf("reading signer id length: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
return nil, nil, nil, ErrMissingSignerIDLength
|
||||
return nil, ErrMissingSignerIDLength
|
||||
}
|
||||
signIDLen := binary.BigEndian.Uint16([]byte{0x00, sigIDLengthBytes[0]})
|
||||
|
||||
@@ -259,70 +280,70 @@ func Read(reader io.Reader) (meta *SU3Meta, content io.Reader, signature io.Read
|
||||
contentLengthBytes := [8]byte{}
|
||||
l, err = reader.Read(contentLengthBytes[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, nil, fmt.Errorf("reading content length: %w", err)
|
||||
return nil, fmt.Errorf("reading content length: %w", err)
|
||||
}
|
||||
if l != 8 {
|
||||
return nil, nil, nil, ErrMissingContentLength
|
||||
return nil, ErrMissingContentLength
|
||||
}
|
||||
contentLen := binary.BigEndian.Uint64(contentLengthBytes[:])
|
||||
meta.ContentLength = contentLen
|
||||
su3.ContentLength = contentLen
|
||||
|
||||
// Unused byte 24.
|
||||
l, err = reader.Read(unused[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, nil, fmt.Errorf("reading unused byte 24: %w", err)
|
||||
return nil, fmt.Errorf("reading unused byte 24: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
return nil, nil, nil, ErrMissingUnusedByte24
|
||||
return nil, ErrMissingUnusedByte24
|
||||
}
|
||||
|
||||
// File type.
|
||||
fileTypeBytes := [1]byte{}
|
||||
l, err = reader.Read(fileTypeBytes[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, nil, fmt.Errorf("reading file type: %w", err)
|
||||
return nil, fmt.Errorf("reading file type: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
return nil, nil, nil, ErrMissingFileType
|
||||
return nil, ErrMissingFileType
|
||||
}
|
||||
fileType, ok := fileTypes[fileTypeBytes[0]]
|
||||
if !ok {
|
||||
return nil, nil, nil, ErrMissingFileType
|
||||
return nil, ErrMissingFileType
|
||||
}
|
||||
meta.FileType = fileType
|
||||
su3.FileType = fileType
|
||||
|
||||
// Unused byte 26.
|
||||
l, err = reader.Read(unused[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, nil, fmt.Errorf("reading unused byte 26: %w", err)
|
||||
return nil, fmt.Errorf("reading unused byte 26: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
return nil, nil, nil, ErrMissingUnusedByte26
|
||||
return nil, ErrMissingUnusedByte26
|
||||
}
|
||||
|
||||
// Content type.
|
||||
contentTypeBytes := [1]byte{}
|
||||
l, err = reader.Read(contentTypeBytes[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, nil, fmt.Errorf("reading content type: %w", err)
|
||||
return nil, fmt.Errorf("reading content type: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
return nil, nil, nil, ErrMissingContentType
|
||||
return nil, ErrMissingContentType
|
||||
}
|
||||
contentType, ok := contentTypes[contentTypeBytes[0]]
|
||||
if !ok {
|
||||
return nil, nil, nil, ErrMissingContentType
|
||||
return nil, ErrMissingContentType
|
||||
}
|
||||
meta.ContentType = contentType
|
||||
su3.ContentType = contentType
|
||||
|
||||
// Unused bytes 28-39.
|
||||
for i := 0; i < 12; i++ {
|
||||
l, err = reader.Read(unused[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, nil, fmt.Errorf("reading unused bytes 28-39: %w", err)
|
||||
return nil, fmt.Errorf("reading unused bytes 28-39: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
return nil, nil, nil, ErrMissingUnusedBytes28To39
|
||||
return nil, ErrMissingUnusedBytes28To39
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,117 +351,105 @@ func Read(reader io.Reader) (meta *SU3Meta, content io.Reader, signature io.Read
|
||||
versionBytes := make([]byte, verLen)
|
||||
l, err = reader.Read(versionBytes[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, nil, fmt.Errorf("reading version: %w", err)
|
||||
return nil, fmt.Errorf("reading version: %w", err)
|
||||
}
|
||||
if l != int(verLen) {
|
||||
return nil, nil, nil, ErrMissingVersion
|
||||
return nil, ErrMissingVersion
|
||||
}
|
||||
version := strings.TrimRight(string(versionBytes), "\x00")
|
||||
meta.Version = version
|
||||
su3.Version = version
|
||||
|
||||
// Signer ID.
|
||||
signerIDBytes := make([]byte, signIDLen)
|
||||
l, err = reader.Read(signerIDBytes[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, nil, fmt.Errorf("reading signer id: %w", err)
|
||||
return nil, fmt.Errorf("reading signer id: %w", err)
|
||||
}
|
||||
if l != int(signIDLen) {
|
||||
return nil, nil, nil, ErrMissingSignerID
|
||||
return nil, ErrMissingSignerID
|
||||
}
|
||||
signerID := string(signerIDBytes)
|
||||
meta.SignerID = signerID
|
||||
su3.SignerID = signerID
|
||||
|
||||
csr := &contentSignatureReader{
|
||||
reader: reader,
|
||||
contentLength: contentLen,
|
||||
signatureLength: sigLen,
|
||||
}
|
||||
// Track the number of bytes read so that the su3Readers know their position.
|
||||
su3.bytesRead = uint64(39 + int(verLen) + int(signIDLen))
|
||||
|
||||
return meta, csr.Content(), csr.Signature(), nil
|
||||
}
|
||||
|
||||
// contentSignatureReader synchronizes reading the content, and then the signature,
|
||||
// out of the same io.Reader that we are reading the SU3 file from. It allows us
|
||||
// to return two io.Readers, one for the content, and one for the signature, and
|
||||
// have them both be read out of the SU3 file io.Reader.
|
||||
type contentSignatureReader struct {
|
||||
sync.Mutex
|
||||
reader io.Reader
|
||||
contentLength uint64
|
||||
signatureLength uint16
|
||||
bytesRead uint64
|
||||
}
|
||||
|
||||
func (csr *contentSignatureReader) Content() io.Reader {
|
||||
return &byteReader{
|
||||
csr: csr,
|
||||
numBytes: csr.contentLength,
|
||||
startByte: 0,
|
||||
su3.contentReader = &su3Reader{
|
||||
su3: su3,
|
||||
startByte: su3.bytesRead,
|
||||
numBytes: su3.ContentLength,
|
||||
outOfBytesError: ErrMissingContent,
|
||||
}
|
||||
}
|
||||
|
||||
func (csr *contentSignatureReader) Signature() io.Reader {
|
||||
return &byteReader{
|
||||
csr: csr,
|
||||
numBytes: uint64(csr.signatureLength),
|
||||
startByte: csr.contentLength,
|
||||
su3.signatureReader = &su3Reader{
|
||||
su3: su3,
|
||||
startByte: su3.bytesRead + su3.ContentLength,
|
||||
numBytes: uint64(su3.SignatureLength),
|
||||
outOfBytesError: ErrMissingSignature,
|
||||
}
|
||||
|
||||
return su3, nil
|
||||
}
|
||||
|
||||
type byteReader struct {
|
||||
csr *contentSignatureReader
|
||||
numBytes uint64
|
||||
type su3Reader struct {
|
||||
su3 *SU3
|
||||
startByte uint64
|
||||
numBytes uint64
|
||||
outOfBytesError error
|
||||
}
|
||||
|
||||
func (br *byteReader) Read(p []byte) (n int, err error) {
|
||||
br.csr.Lock()
|
||||
defer br.csr.Unlock()
|
||||
func (r *su3Reader) Read(p []byte) (n int, err error) {
|
||||
r.su3.mut.Lock()
|
||||
defer r.su3.mut.Unlock()
|
||||
|
||||
// If we have already read past where we are supposed to, return an error.
|
||||
// This would happen if someone read the signature before reading the content,
|
||||
// and then tried to read the content.
|
||||
if br.csr.bytesRead > br.startByte {
|
||||
if r.su3.bytesRead > r.startByte {
|
||||
return 0, errors.New("out of bytes, maybe you read the signature before you read the content")
|
||||
}
|
||||
|
||||
// If we have not read up until where we are supposed to, throw away the bytes.
|
||||
// This would happen if someone read the signature before reading the content.
|
||||
// We want to allow them to read the signature. The above condition will return
|
||||
// an error if they try to read the content.
|
||||
if br.csr.bytesRead < br.startByte {
|
||||
bytesToThrowAway := br.startByte - br.csr.bytesRead
|
||||
// an error if they try to read the content after the bytes have been thrown away.
|
||||
if r.su3.bytesRead < r.startByte {
|
||||
bytesToThrowAway := r.startByte - r.su3.bytesRead
|
||||
throwaway := make([]byte, bytesToThrowAway)
|
||||
l, err := br.csr.reader.Read(throwaway)
|
||||
br.csr.bytesRead += uint64(l)
|
||||
l, err := r.su3.reader.Read(throwaway)
|
||||
r.su3.bytesRead += uint64(l)
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return 0, fmt.Errorf("reading throwaway bytes: %w", err)
|
||||
}
|
||||
if l != int(bytesToThrowAway) {
|
||||
return 0, br.outOfBytesError
|
||||
return 0, r.outOfBytesError
|
||||
}
|
||||
}
|
||||
|
||||
// We are at the correct position.
|
||||
// If numBytes is 0, we have read all the bytes.
|
||||
if br.numBytes == 0 {
|
||||
if r.numBytes == 0 {
|
||||
// TODO when we finish reading content, we should then read the signature and verify it.
|
||||
// If the signature doesn't match, we would return ErrInvalidSignature here.
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
// Otherwise, we have some bytes to read.
|
||||
numBytesToRead := len(p)
|
||||
if numBytesToRead > int(br.numBytes) {
|
||||
numBytesToRead = int(br.numBytes)
|
||||
if numBytesToRead > int(r.numBytes) {
|
||||
numBytesToRead = int(r.numBytes)
|
||||
}
|
||||
l, err := br.csr.reader.Read(p[:numBytesToRead])
|
||||
l, err := r.su3.reader.Read(p[:numBytesToRead])
|
||||
|
||||
// Advance the counters to keep track of how many bytes we've read.
|
||||
br.csr.bytesRead += uint64(l)
|
||||
br.numBytes = br.numBytes - uint64(l)
|
||||
br.startByte = br.startByte + uint64(l)
|
||||
r.su3.bytesRead += uint64(l)
|
||||
r.numBytes = r.numBytes - uint64(l)
|
||||
r.startByte = r.startByte + uint64(l)
|
||||
|
||||
// We should have read the correct number of bytes.
|
||||
if l < numBytesToRead {
|
||||
return l, br.outOfBytesError
|
||||
return l, r.outOfBytesError
|
||||
}
|
||||
|
||||
return l, err
|
||||
}
|
||||
|
@@ -38,8 +38,9 @@ func TestRead(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
reader io.Reader
|
||||
key interface{}
|
||||
wantErr string
|
||||
wantMeta *SU3Meta
|
||||
wantSU3 *SU3
|
||||
wantContent []byte
|
||||
wantSignature []byte
|
||||
}{
|
||||
@@ -449,7 +450,8 @@ func TestRead(t *testing.T) {
|
||||
[]byte("apeace rules"), // Content
|
||||
[]byte{0x99}, // Signature
|
||||
)),
|
||||
wantMeta: &SU3Meta{
|
||||
key: nil,
|
||||
wantSU3: &SU3{
|
||||
SignatureType: ECDSA_SHA512_P521,
|
||||
SignatureLength: 1,
|
||||
ContentLength: 12,
|
||||
@@ -464,7 +466,8 @@ func TestRead(t *testing.T) {
|
||||
{
|
||||
name: "reseed-i2pgit.su3",
|
||||
reader: fileReader(t, "testdata/reseed-i2pgit.su3"),
|
||||
wantMeta: &SU3Meta{
|
||||
key: nil,
|
||||
wantSU3: &SU3{
|
||||
SignatureType: RSA_SHA512_4096,
|
||||
SignatureLength: 512,
|
||||
ContentLength: 80138,
|
||||
@@ -480,12 +483,12 @@ func TestRead(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
meta, contentReader, signatureReader, err := Read(test.reader)
|
||||
su3, err := Read(test.reader)
|
||||
var content, signature []byte
|
||||
if err == nil {
|
||||
content, err = ioutil.ReadAll(contentReader)
|
||||
content, err = ioutil.ReadAll(su3.Content(test.key))
|
||||
if err == nil {
|
||||
signature, err = ioutil.ReadAll(signatureReader)
|
||||
signature, err = ioutil.ReadAll(su3.Signature())
|
||||
}
|
||||
}
|
||||
if test.wantErr != "" && err == nil {
|
||||
@@ -495,7 +498,13 @@ func TestRead(t *testing.T) {
|
||||
} else if err != nil {
|
||||
assert.Nil(t, err, "expected nil error")
|
||||
} else {
|
||||
assert.Equal(t, test.wantMeta, meta, "expected metdata to match")
|
||||
assert.Equal(t, test.wantSU3.SignatureType, su3.SignatureType, "expected SignatureType to match")
|
||||
assert.Equal(t, test.wantSU3.SignatureLength, su3.SignatureLength, "expected SignatureLength to match")
|
||||
assert.Equal(t, test.wantSU3.ContentLength, su3.ContentLength, "expected ContentLength to match")
|
||||
assert.Equal(t, test.wantSU3.FileType, su3.FileType, "expected FileType to match")
|
||||
assert.Equal(t, test.wantSU3.ContentType, su3.ContentType, "expected ContentType to match")
|
||||
assert.Equal(t, test.wantSU3.Version, su3.Version, "expected Version to match")
|
||||
assert.Equal(t, test.wantSU3.SignerID, su3.SignerID, "expected SignerID to match")
|
||||
assert.Equal(t, test.wantContent, content, "expected content to match")
|
||||
assert.Equal(t, test.wantSignature, signature, "expected signature to match")
|
||||
}
|
||||
@@ -507,15 +516,15 @@ func TestReadSignatureFirst(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
reader := fileReader(t, "testdata/reseed-i2pgit.su3")
|
||||
_, contentReader, signatureReader, err := Read(reader)
|
||||
su3, err := Read(reader)
|
||||
assert.Nil(err)
|
||||
|
||||
// Read only the signature.
|
||||
sig, err := ioutil.ReadAll(signatureReader)
|
||||
sig, err := ioutil.ReadAll(su3.Signature())
|
||||
assert.Nil(err)
|
||||
assert.Equal(fileBytes(t, "testdata/reseed-i2pgit-signature"), sig)
|
||||
|
||||
// Reading content should give an error.
|
||||
_, err = ioutil.ReadAll(contentReader)
|
||||
_, err = ioutil.ReadAll(su3.Content(nil))
|
||||
assert.NotNil(err)
|
||||
}
|
||||
|
Reference in New Issue
Block a user