213 lines
6.5 KiB
Go
213 lines
6.5 KiB
Go
|
package protocol
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"crypto"
|
||
|
"crypto/rand"
|
||
|
"crypto/rsa"
|
||
|
"crypto/tls"
|
||
|
"crypto/x509"
|
||
|
"crypto/x509/pkix"
|
||
|
"encoding/asn1"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"time"
|
||
|
|
||
|
oid "github.com/InfiniteLoopSpace/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) {
|
||
|
|
||
|
return recInfo.KTRI.decryptKey(keyPair)
|
||
|
|
||
|
}
|
||
|
|
||
|
//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
|
||
|
|
||
|
//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) {
|
||
|
alg := oid.PublicKeyAlgorithmToEncrytionAlgorithm[keyPair.Leaf.PublicKeyAlgorithm].Algorithm
|
||
|
if ktri.KeyEncryptionAlgorithm.Algorithm.Equal(alg) {
|
||
|
|
||
|
decrypter := keyPair.PrivateKey.(crypto.Decrypter)
|
||
|
return decrypter.Decrypt(rand.Reader, ktri.EncryptedKey, nil)
|
||
|
|
||
|
}
|
||
|
log.Println("Key encrytion algorithm not matching")
|
||
|
}
|
||
|
case 2:
|
||
|
if bytes.Equal(ski, ktri.Rid.SKI) {
|
||
|
alg := oid.PublicKeyAlgorithmToEncrytionAlgorithm[keyPair.Leaf.PublicKeyAlgorithm].Algorithm
|
||
|
if ktri.KeyEncryptionAlgorithm.Algorithm.Equal(alg) {
|
||
|
if alg.Equal(oid.EncryptionAlgorithmRSA) {
|
||
|
return rsa.DecryptPKCS1v15(rand.Reader, keyPair.PrivateKey.(*rsa.PrivateKey), ktri.EncryptedKey)
|
||
|
}
|
||
|
log.Println("Unsupported key encrytion algorithm")
|
||
|
}
|
||
|
log.Println("Key encrytion algorithm not matching")
|
||
|
}
|
||
|
default:
|
||
|
fmt.Println(ktri.Version)
|
||
|
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) RecipientInfo {
|
||
|
version := 0 //issuerAndSerialNumber
|
||
|
|
||
|
rid := RecipientIdentifier{}
|
||
|
|
||
|
switch version {
|
||
|
case 0:
|
||
|
ias, err := NewIssuerAndSerialNumber(recipient)
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
rid.IAS = ias
|
||
|
case 2:
|
||
|
rid.SKI = recipient.SubjectKeyId
|
||
|
}
|
||
|
|
||
|
kea := oid.PublicKeyAlgorithmToEncrytionAlgorithm[recipient.PublicKeyAlgorithm]
|
||
|
if _, ok := oid.PublicKeyAlgorithmToEncrytionAlgorithm[recipient.PublicKeyAlgorithm]; !ok {
|
||
|
log.Fatal("NewRecipientInfo: PublicKeyAlgorithm not supported")
|
||
|
}
|
||
|
|
||
|
encrypted, _ := encryptKey(key, recipient)
|
||
|
|
||
|
info := RecipientInfo{
|
||
|
KTRI: KeyTransRecipientInfo{
|
||
|
Version: version,
|
||
|
Rid: rid,
|
||
|
KeyEncryptionAlgorithm: kea,
|
||
|
EncryptedKey: encrypted,
|
||
|
}}
|
||
|
return info
|
||
|
}
|
||
|
|
||
|
func encryptKey(key []byte, recipient *x509.Certificate) ([]byte, error) {
|
||
|
if pub := recipient.PublicKey.(*rsa.PublicKey); pub != nil {
|
||
|
return rsa.EncryptPKCS1v15(rand.Reader, pub, key)
|
||
|
}
|
||
|
return nil, ErrUnsupportedAlgorithm
|
||
|
}
|
||
|
|
||
|
// 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"`
|
||
|
}
|