...

Source file src/github.com/sassoftware/relic/lib/x509tools/rsapss.go

Documentation: github.com/sassoftware/relic/lib/x509tools

     1  //
     2  // Copyright (c) SAS Institute Inc.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  //
    16  
    17  package x509tools
    18  
    19  import (
    20  	"crypto"
    21  	"crypto/rsa"
    22  	"crypto/x509/pkix"
    23  	"encoding/asn1"
    24  	"errors"
    25  )
    26  
    27  // pssParameters reflects the parameters in an AlgorithmIdentifier that
    28  // specifies RSA PSS. See https://tools.ietf.org/html/rfc3447#appendix-A.2.3
    29  type pssParameters struct {
    30  	// The following three fields are not marked as
    31  	// optional because the default values specify SHA-1,
    32  	// which is no longer suitable for use in signatures.
    33  	Hash         pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"`
    34  	MGF          pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"`
    35  	SaltLength   int                      `asn1:"explicit,tag:2"`
    36  	TrailerField int                      `asn1:"optional,explicit,tag:3,default:1"`
    37  }
    38  
    39  func MarshalRSAPSSParameters(pub *rsa.PublicKey, opts *rsa.PSSOptions) (asn1.RawValue, error) {
    40  	hashAlg, ok := PkixDigestAlgorithm(opts.Hash)
    41  	if !ok {
    42  		return asn1.RawValue{}, errors.New("unsupported digest algorithm")
    43  	}
    44  	hashRaw, err := asn1.Marshal(hashAlg)
    45  	if err != nil {
    46  		return asn1.RawValue{}, err
    47  	}
    48  	saltLength := opts.SaltLength
    49  	switch saltLength {
    50  	case rsa.PSSSaltLengthAuto:
    51  		saltLength = (pub.N.BitLen()+7)/8 - 2 - opts.Hash.Size()
    52  	case rsa.PSSSaltLengthEqualsHash:
    53  		saltLength = opts.Hash.Size()
    54  	}
    55  	params := pssParameters{
    56  		Hash: hashAlg,
    57  		MGF: pkix.AlgorithmIdentifier{
    58  			Algorithm:  OidMGF1,
    59  			Parameters: asn1.RawValue{FullBytes: hashRaw},
    60  		},
    61  		SaltLength:   saltLength,
    62  		TrailerField: 1,
    63  	}
    64  	serialized, err := asn1.Marshal(params)
    65  	if err != nil {
    66  		return asn1.RawValue{}, err
    67  	}
    68  	return asn1.RawValue{FullBytes: serialized}, nil
    69  }
    70  
    71  func UnmarshalRSAPSSParameters(hash crypto.Hash, raw asn1.RawValue) (*rsa.PSSOptions, error) {
    72  	hashOid, ok := HashOids[hash]
    73  	if !ok {
    74  		return nil, errors.New("unsupported digest algorithm")
    75  	}
    76  	if raw.Tag == asn1.TagNull {
    77  		// defaults
    78  		if hash != crypto.SHA1 {
    79  			return nil, errors.New("RSA-PSS parameters not provided but digest type is not SHA-1")
    80  		}
    81  		return &rsa.PSSOptions{Hash: crypto.SHA1, SaltLength: 20}, nil
    82  	}
    83  	var params pssParameters
    84  	if rest, err := asn1.Unmarshal(raw.FullBytes, &params); err != nil || len(rest) > 0 {
    85  		return nil, errors.New("invalid RSA-PSS parameters")
    86  	}
    87  	// validate that all hash OIDs match
    88  	if !params.Hash.Algorithm.Equal(hashOid) {
    89  		return nil, errors.New("digest type mismatch in RSA-PSS parameters")
    90  	}
    91  	if !params.MGF.Algorithm.Equal(OidMGF1) {
    92  		return nil, errors.New("unsupported MGF in RSA-PSS parameters")
    93  	}
    94  	var mgfDigest pkix.AlgorithmIdentifier
    95  	if rest, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgfDigest); err != nil || len(rest) > 0 {
    96  		return nil, errors.New("invalid RSA-PSS parameters")
    97  	}
    98  	if !mgfDigest.Algorithm.Equal(hashOid) {
    99  		return nil, errors.New("digest type mismatch in RSA-PSS parameters")
   100  	}
   101  	if params.TrailerField != 0 && params.TrailerField != 1 {
   102  		return nil, errors.New("invalid RSA-PSS parameters")
   103  	}
   104  	if params.SaltLength == 0 {
   105  		params.SaltLength = hash.Size()
   106  	}
   107  	return &rsa.PSSOptions{Hash: hash, SaltLength: params.SaltLength}, nil
   108  }
   109  

View as plain text