go_S-MIME/cms/protocol/reciepientinfo.go

259 lines
7.5 KiB
Go

package protocol
import (
"bytes"
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"errors"
"log"
"time"
oid "git.ma-al.com/goc_marek/go_S-MIME/oid"
)
// RecipientInfo ::= CHOICE {
// ktri KeyTransRecipientInfo,
// kari [1] KeyAgreeRecipientInfo,
// kekri [2] KEKRecipientInfo,
// pwri [3] PasswordRecipientInfo,
// ori [4] OtherRecipientInfo }
type RecipientInfo struct {
KTRI KeyTransRecipientInfo `asn1:"optional"`
KARI KeyAgreeRecipientInfo `asn1:"optional,tag:1"` //KeyAgreeRecipientInfo
KEKRI asn1.RawValue `asn1:"optional,tag:2"`
PWRI asn1.RawValue `asn1:"optional,tag:3"`
ORI asn1.RawValue `asn1:"optional,tag:4"`
}
func (recInfo *RecipientInfo) decryptKey(keyPair tls.Certificate) (key []byte, err error) {
key, err = recInfo.KTRI.decryptKey(keyPair)
if key != nil || (err != nil && err != ErrUnsupported) {
return
}
key, err = recInfo.KARI.decryptKey(keyPair)
return
}
// KeyTransRecipientInfo ::= SEQUENCE {
// version CMSVersion, -- always set to 0 or 2
// rid RecipientIdentifier,
// keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
// encryptedKey EncryptedKey }
type KeyTransRecipientInfo struct {
Version int
Rid RecipientIdentifier `asn1:"choice"`
KeyEncryptionAlgorithm pkix.AlgorithmIdentifier
EncryptedKey []byte
}
func (ktri *KeyTransRecipientInfo) decryptKey(keyPair tls.Certificate) (key []byte, err error) {
ias, err := NewIssuerAndSerialNumber(keyPair.Leaf)
if err != nil {
return
}
ski := keyPair.Leaf.SubjectKeyId
certPubAlg := oid.PublicKeyAlgorithmToEncrytionAlgorithm[keyPair.Leaf.PublicKeyAlgorithm].Algorithm
var decOpts crypto.DecrypterOpts
pkcs15CertwithOAEP := false
if ktri.KeyEncryptionAlgorithm.Algorithm.Equal(oid.EncryptionAlgorithmRSAESOAEP) {
if certPubAlg.Equal(oid.EncryptionAlgorithmRSA) {
pkcs15CertwithOAEP = true
}
decOpts, err = parseRSAESOAEPparams(ktri.KeyEncryptionAlgorithm.Parameters.FullBytes)
if err != nil {
return
}
}
//version is the syntax version number. If the SignerIdentifier is
//the CHOICE issuerAndSerialNumber, then the version MUST be 1. If
//the SignerIdentifier is subjectKeyIdentifier, then the version
//MUST be 3.
switch ktri.Version {
case 0:
if ias.Equal(ktri.Rid.IAS) {
if ktri.KeyEncryptionAlgorithm.Algorithm.Equal(certPubAlg) || pkcs15CertwithOAEP {
decrypter := keyPair.PrivateKey.(crypto.Decrypter)
return decrypter.Decrypt(rand.Reader, ktri.EncryptedKey, decOpts)
}
log.Println("Key encrytion algorithm not matching")
}
case 2:
if bytes.Equal(ski, ktri.Rid.SKI) {
if ktri.KeyEncryptionAlgorithm.Algorithm.Equal(certPubAlg) || pkcs15CertwithOAEP {
decrypter := keyPair.PrivateKey.(crypto.Decrypter)
return decrypter.Decrypt(rand.Reader, ktri.EncryptedKey, decOpts)
}
log.Println("Key encrytion algorithm not matching")
}
default:
return nil, ErrUnsupported
}
return nil, nil
}
// RecipientIdentifier ::= CHOICE {
// issuerAndSerialNumber IssuerAndSerialNumber,
// subjectKeyIdentifier [0] SubjectKeyIdentifier }
type RecipientIdentifier struct {
IAS IssuerAndSerialNumber `asn1:"optional"`
SKI []byte `asn1:"optional,tag:0"`
}
// NewRecipientInfo creates RecipientInfo for giben recipient and key.
func NewRecipientInfo(recipient *x509.Certificate, key []byte) (info RecipientInfo, err error) {
switch recipient.PublicKeyAlgorithm {
case x509.RSA:
var ktri KeyTransRecipientInfo
ktri, err = encryptKeyRSA(key, recipient)
if err != nil {
return
}
info = RecipientInfo{KTRI: ktri}
case x509.ECDSA:
var kari KeyAgreeRecipientInfo
kari, err = encryptKeyECDH(key, recipient)
if err != nil {
return
}
info = RecipientInfo{KARI: kari}
default:
err = errors.New("Public key algorithm not supported")
}
return
}
func encryptKeyRSA(key []byte, recipient *x509.Certificate) (ktri KeyTransRecipientInfo, err error) {
ktri.Version = 0 //issuerAndSerialNumber
switch ktri.Version {
case 0:
ias, err := NewIssuerAndSerialNumber(recipient)
if err != nil {
log.Fatal(err)
}
ktri.Rid.IAS = ias
case 2:
ktri.Rid.SKI = recipient.SubjectKeyId
}
if pub := recipient.PublicKey.(*rsa.PublicKey); pub != nil {
if isRSAPSS(recipient) {
hash := crypto.SHA256
var oaepparam RSAESOAEPparams
oaepparam, err = newRSAESOAEPparams(hash)
if err != nil {
return
}
var oaepparamRV asn1.RawValue
oaepparamRV, err = RawValue(oaepparam)
if err != nil {
return
}
ktri.KeyEncryptionAlgorithm = pkix.AlgorithmIdentifier{Algorithm: oid.EncryptionAlgorithmRSAESOAEP, Parameters: oaepparamRV}
h := hash.New()
ktri.EncryptedKey, err = rsa.EncryptOAEP(h, rand.Reader, pub, key, nil)
return
}
ktri.KeyEncryptionAlgorithm = pkix.AlgorithmIdentifier{Algorithm: oid.EncryptionAlgorithmRSA}
ktri.EncryptedKey, err = rsa.EncryptPKCS1v15(rand.Reader, pub, key)
return
}
err = ErrUnsupportedAlgorithm
return
}
// ErrUnsupportedAlgorithm is returned if the algorithm is unsupported.
var ErrUnsupportedAlgorithm = errors.New("cms: cannot decrypt data: unsupported algorithm")
// KeyAgreeRecipientInfo ::= SEQUENCE {
// version CMSVersion, -- always set to 3
// originator [0] EXPLICIT OriginatorIdentifierOrKey,
// ukm [1] EXPLICIT UserKeyingMaterial OPTIONAL,
// keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
// recipientEncryptedKeys RecipientEncryptedKeys }
type KeyAgreeRecipientInfo struct {
Version int
Originator OriginatorIdentifierOrKey `asn1:"explicit,choice,tag:0"`
UKM []byte `asn1:"explicit,optional,tag:1"`
KeyEncryptionAlgorithm pkix.AlgorithmIdentifier ``
RecipientEncryptedKeys []RecipientEncryptedKey `asn1:"sequence"` //RecipientEncryptedKeys ::= SEQUENCE OF RecipientEncryptedKey
}
// OriginatorIdentifierOrKey ::= CHOICE {
// issuerAndSerialNumber IssuerAndSerialNumber,
// subjectKeyIdentifier [0] SubjectKeyIdentifier,
// originatorKey [1] OriginatorPublicKey }
type OriginatorIdentifierOrKey struct {
IAS IssuerAndSerialNumber `asn1:"optional"`
SKI []byte `asn1:"optional,tag:0"`
OriginatorKey OriginatorPublicKey `asn1:"optional,tag:1"`
}
// OriginatorPublicKey ::= SEQUENCE {
// algorithm AlgorithmIdentifier,
// publicKey BIT STRING
type OriginatorPublicKey struct {
Algorithm pkix.AlgorithmIdentifier
PublicKey asn1.BitString
}
// RecipientEncryptedKey ::= SEQUENCE {
// rid KeyAgreeRecipientIdentifier,
// encryptedKey EncryptedKey }
type RecipientEncryptedKey struct {
RID KeyAgreeRecipientIdentifier `asn1:"choice"`
EncryptedKey []byte
}
// KeyAgreeRecipientIdentifier ::= CHOICE {
// issuerAndSerialNumber IssuerAndSerialNumber,
// rKeyId [0] IMPLICIT RecipientKeyIdentifier }
type KeyAgreeRecipientIdentifier struct {
IAS IssuerAndSerialNumber `asn1:"optional"`
RKeyID RecipientKeyIdentifier `asn1:"optional,tag:0"`
}
// RecipientKeyIdentifier ::= SEQUENCE {
// subjectKeyIdentifier SubjectKeyIdentifier,
// date GeneralizedTime OPTIONAL,
// other OtherKeyAttribute OPTIONAL }
type RecipientKeyIdentifier struct {
SubjectKeyIdentifier []byte //SubjectKeyIdentifier ::= OCTET STRING
Date time.Time `asn1:"optional"`
Other OtherKeyAttribute `asn1:"optional"`
}
// OtherKeyAttribute ::= SEQUENCE {
// keyAttrId OBJECT IDENTIFIER,
// keyAttr ANY DEFINED BY keyAttrId OPTIONAL }
type OtherKeyAttribute struct {
KeyAttrID asn1.ObjectIdentifier
KeyAttr asn1.RawValue `asn1:"optional"`
}