...

Source file src/github.com/sassoftware/relic/lib/appmanifest/publictoken.go

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

     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 appmanifest
    18  
    19  import (
    20  	"bytes"
    21  	"crypto"
    22  	"crypto/ecdsa"
    23  	"crypto/elliptic"
    24  	"crypto/rsa"
    25  	"encoding/binary"
    26  	"encoding/hex"
    27  	"errors"
    28  	"math/big"
    29  
    30  	"github.com/sassoftware/relic/lib/certloader"
    31  	"github.com/sassoftware/relic/lib/x509tools"
    32  )
    33  
    34  func PublisherIdentity(cert *certloader.Certificate) (string, string, error) {
    35  	issuer := cert.Issuer()
    36  	if issuer == nil {
    37  		return "", "", errors.New("unable to find issuer certificate in chain")
    38  	}
    39  	aki, err := x509tools.SubjectKeyID(issuer.PublicKey)
    40  	if err != nil {
    41  		return "", "", err
    42  	}
    43  	name := x509tools.FormatPkixName(cert.Leaf.RawSubject, x509tools.NameStyleMsOsco)
    44  	return name, hex.EncodeToString(aki), nil
    45  }
    46  
    47  const (
    48  	snkRsaPub     = 0x06
    49  	snkRsaPriv    = 0x07
    50  	snkRsaVersion = 0x02
    51  	// https://msdn.microsoft.com/en-us/library/windows/desktop/aa375549(v=vs.85).aspx
    52  	calgRsaSign = 0x2400 // CALG_RSA_SIGN
    53  	calgSha1    = 0x8004 // CALG_SHA1
    54  	calgEcdsa   = 0x2203 // CALG_ECDSA
    55  	// bcrypt.h
    56  	bcryptRsaPubMagic  = 0x31415352 // BCRYPT_RSAPUBLIC_MAGIC
    57  	bcryptEcdsaPubP256 = 0x31534345 // BCRYPT_ECDSA_PUBLIC_P256_MAGIC
    58  	bcryptEcdsaPubP384 = 0x33534345 // BCRYPT_ECDSA_PUBLIC_P384_MAGIC
    59  	bcryptEcdsaPubP521 = 0x35534345 // BCRYPT_ECDSA_PUBLIC_P521_MAGIC
    60  )
    61  
    62  type snkHeader struct {
    63  	PubAlgorithm  uint32
    64  	HashAlgorithm uint32
    65  	BlobSize      uint32
    66  	KeyType       uint8
    67  	Version       uint8
    68  	Reserved      uint16
    69  	PubAlgorithm2 uint32
    70  }
    71  
    72  type blobRsaPub struct {
    73  	snkHeader
    74  	// BCRYPT_RSAKEY_BLOB
    75  	KeyMagic    uint32
    76  	BitLength   uint32
    77  	PubExponent uint32
    78  } // N [BitLength/8]byte
    79  
    80  type blobEcdsaPub struct {
    81  	snkHeader
    82  	// BCRYPT_ECCKEY_BLOB
    83  	KeyMagic   uint32
    84  	ByteLength uint32
    85  } // X, Y [ByteLength]byte
    86  
    87  // Calculate the publicKeyToken from a public key. This involves mangling it
    88  // into a .snk file format, then hashing it.
    89  //
    90  // http://www.developerfusion.com/article/84422/the-key-to-strong-names/
    91  func PublicKeyToken(pubKey crypto.PublicKey) (string, error) {
    92  	snk, err := PublicKeyToSnk(pubKey)
    93  	if err != nil {
    94  		return "", err
    95  	}
    96  	d := crypto.SHA1.New()
    97  	d.Write(snk)
    98  	// token is the low 64 bits of sum decoded as a little-endian number, or in
    99  	// other words the last 8 bytes in reverse order
   100  	sum := d.Sum(nil)
   101  	token := make([]byte, 8)
   102  	for i := 0; i < 8; i++ {
   103  		token[i] = sum[19-i]
   104  	}
   105  	return hex.EncodeToString(token), nil
   106  }
   107  
   108  // Convert public key to "snk" format
   109  func PublicKeyToSnk(pubKey crypto.PublicKey) ([]byte, error) {
   110  	var buf bytes.Buffer
   111  	switch k := pubKey.(type) {
   112  	case *rsa.PublicKey:
   113  		modulus := bigIntToLE(k.N)
   114  		if err := binary.Write(&buf, binary.LittleEndian, blobRsaPub{
   115  			snkHeader: snkHeader{
   116  				PubAlgorithm:  calgRsaSign,
   117  				HashAlgorithm: calgSha1,
   118  				BlobSize:      uint32(20 + len(modulus)),
   119  				KeyType:       snkRsaPub,
   120  				Version:       snkRsaVersion,
   121  				PubAlgorithm2: calgRsaSign,
   122  			},
   123  			KeyMagic:    bcryptRsaPubMagic,
   124  			BitLength:   uint32(8 * len(modulus)),
   125  			PubExponent: uint32(k.E),
   126  		}); err != nil {
   127  			return nil, nil
   128  		}
   129  		buf.Write(modulus)
   130  	case *ecdsa.PublicKey:
   131  		// TODO: This is a best guess based on piecing together various
   132  		// Microsoft documentation and header values, but some pieces are still
   133  		// missing. ECDSA isn't supported for strong name signing, and
   134  		// calcuating the publicKeyToken for SN is the only reason this
   135  		// function is even here.
   136  		var keyMagic uint32
   137  		switch k.Curve {
   138  		case elliptic.P256():
   139  			keyMagic = bcryptEcdsaPubP256
   140  		case elliptic.P384():
   141  			keyMagic = bcryptEcdsaPubP384
   142  		case elliptic.P521():
   143  			keyMagic = bcryptEcdsaPubP521
   144  		default:
   145  			return nil, errors.New("unsupported ECDSA curve")
   146  		}
   147  		// TODO: are these supposed to be big-endian? the documentation for
   148  		// BCRYPT_ECCKEY_BLOB says so, but it also said that about the RSA one
   149  		// and yet the SNK format actually uses little endian...
   150  		x := k.X.Bytes()
   151  		y := k.Y.Bytes()
   152  		if err := binary.Write(&buf, binary.LittleEndian, blobEcdsaPub{
   153  			snkHeader: snkHeader{
   154  				PubAlgorithm:  calgEcdsa,
   155  				HashAlgorithm: calgSha1,
   156  				BlobSize:      uint32(12 + 2*len(x)),
   157  				KeyType:       snkRsaPub,     // TODO
   158  				Version:       snkRsaVersion, // TODO
   159  				PubAlgorithm2: calgEcdsa,
   160  			},
   161  			KeyMagic:   keyMagic,
   162  			ByteLength: uint32(len(x)),
   163  		}); err != nil {
   164  			return nil, nil
   165  		}
   166  		buf.Write(x)
   167  		buf.Write(y)
   168  	default:
   169  		return nil, errors.New("unsupported key type for strong name signing")
   170  	}
   171  	return buf.Bytes(), nil
   172  }
   173  
   174  func bigIntToLE(x *big.Int) []byte {
   175  	b := x.Bytes()
   176  	for i := 0; i < len(b)/2; i++ {
   177  		j := len(b) - i - 1
   178  		b[i], b[j] = b[j], b[i]
   179  	}
   180  	return b
   181  }
   182  

View as plain text