...

Source file src/golang.org/x/crypto/openpgp/packet/signature_v3.go

Documentation: golang.org/x/crypto/openpgp/packet

     1  // Copyright 2013 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package packet
     6  
     7  import (
     8  	"crypto"
     9  	"encoding/binary"
    10  	"fmt"
    11  	"io"
    12  	"strconv"
    13  	"time"
    14  
    15  	"golang.org/x/crypto/openpgp/errors"
    16  	"golang.org/x/crypto/openpgp/s2k"
    17  )
    18  
    19  // SignatureV3 represents older version 3 signatures. These signatures are less secure
    20  // than version 4 and should not be used to create new signatures. They are included
    21  // here for backwards compatibility to read and validate with older key material.
    22  // See RFC 4880, section 5.2.2.
    23  type SignatureV3 struct {
    24  	SigType      SignatureType
    25  	CreationTime time.Time
    26  	IssuerKeyId  uint64
    27  	PubKeyAlgo   PublicKeyAlgorithm
    28  	Hash         crypto.Hash
    29  	HashTag      [2]byte
    30  
    31  	RSASignature     parsedMPI
    32  	DSASigR, DSASigS parsedMPI
    33  }
    34  
    35  func (sig *SignatureV3) parse(r io.Reader) (err error) {
    36  	// RFC 4880, section 5.2.2
    37  	var buf [8]byte
    38  	if _, err = readFull(r, buf[:1]); err != nil {
    39  		return
    40  	}
    41  	if buf[0] < 2 || buf[0] > 3 {
    42  		err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0])))
    43  		return
    44  	}
    45  	if _, err = readFull(r, buf[:1]); err != nil {
    46  		return
    47  	}
    48  	if buf[0] != 5 {
    49  		err = errors.UnsupportedError(
    50  			"invalid hashed material length " + strconv.Itoa(int(buf[0])))
    51  		return
    52  	}
    53  
    54  	// Read hashed material: signature type + creation time
    55  	if _, err = readFull(r, buf[:5]); err != nil {
    56  		return
    57  	}
    58  	sig.SigType = SignatureType(buf[0])
    59  	t := binary.BigEndian.Uint32(buf[1:5])
    60  	sig.CreationTime = time.Unix(int64(t), 0)
    61  
    62  	// Eight-octet Key ID of signer.
    63  	if _, err = readFull(r, buf[:8]); err != nil {
    64  		return
    65  	}
    66  	sig.IssuerKeyId = binary.BigEndian.Uint64(buf[:])
    67  
    68  	// Public-key and hash algorithm
    69  	if _, err = readFull(r, buf[:2]); err != nil {
    70  		return
    71  	}
    72  	sig.PubKeyAlgo = PublicKeyAlgorithm(buf[0])
    73  	switch sig.PubKeyAlgo {
    74  	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA:
    75  	default:
    76  		err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo)))
    77  		return
    78  	}
    79  	var ok bool
    80  	if sig.Hash, ok = s2k.HashIdToHash(buf[1]); !ok {
    81  		return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2])))
    82  	}
    83  
    84  	// Two-octet field holding left 16 bits of signed hash value.
    85  	if _, err = readFull(r, sig.HashTag[:2]); err != nil {
    86  		return
    87  	}
    88  
    89  	switch sig.PubKeyAlgo {
    90  	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
    91  		sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r)
    92  	case PubKeyAlgoDSA:
    93  		if sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r); err != nil {
    94  			return
    95  		}
    96  		sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r)
    97  	default:
    98  		panic("unreachable")
    99  	}
   100  	return
   101  }
   102  
   103  // Serialize marshals sig to w. Sign, SignUserId or SignKey must have been
   104  // called first.
   105  func (sig *SignatureV3) Serialize(w io.Writer) (err error) {
   106  	buf := make([]byte, 8)
   107  
   108  	// Write the sig type and creation time
   109  	buf[0] = byte(sig.SigType)
   110  	binary.BigEndian.PutUint32(buf[1:5], uint32(sig.CreationTime.Unix()))
   111  	if _, err = w.Write(buf[:5]); err != nil {
   112  		return
   113  	}
   114  
   115  	// Write the issuer long key ID
   116  	binary.BigEndian.PutUint64(buf[:8], sig.IssuerKeyId)
   117  	if _, err = w.Write(buf[:8]); err != nil {
   118  		return
   119  	}
   120  
   121  	// Write public key algorithm, hash ID, and hash value
   122  	buf[0] = byte(sig.PubKeyAlgo)
   123  	hashId, ok := s2k.HashToHashId(sig.Hash)
   124  	if !ok {
   125  		return errors.UnsupportedError(fmt.Sprintf("hash function %v", sig.Hash))
   126  	}
   127  	buf[1] = hashId
   128  	copy(buf[2:4], sig.HashTag[:])
   129  	if _, err = w.Write(buf[:4]); err != nil {
   130  		return
   131  	}
   132  
   133  	if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil {
   134  		return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize")
   135  	}
   136  
   137  	switch sig.PubKeyAlgo {
   138  	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
   139  		err = writeMPIs(w, sig.RSASignature)
   140  	case PubKeyAlgoDSA:
   141  		err = writeMPIs(w, sig.DSASigR, sig.DSASigS)
   142  	default:
   143  		panic("impossible")
   144  	}
   145  	return
   146  }
   147  

View as plain text