You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1271 lines
33 KiB
1271 lines
33 KiB
2 years ago
|
/* PKCS#7 parser
|
||
|
*
|
||
|
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||
|
* Written by David Howells (dhowells@redhat.com)
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU General Public Licence
|
||
|
* as published by the Free Software Foundation; either version
|
||
|
* 2 of the Licence, or (at your option) any later version.
|
||
|
*/
|
||
|
|
||
|
//#define pr_fmt(fmt) "PKCS7: "fmt
|
||
|
//#include <linux/kernel.h>
|
||
|
//#include <linux/export.h>
|
||
|
//#include <linux/slab.h>
|
||
|
//#include <linux/err.h>
|
||
|
//#include <linux/oid_registry.h>
|
||
|
//#include <crypto/public_key.h>
|
||
|
//#include "pkcs7_parser.h"
|
||
|
//#include "pkcs7-asn1.h"
|
||
|
|
||
|
#include "pkcs7_parser.h"
|
||
|
#include "errno.h"
|
||
|
#include "asn1_ber_bytecode.h"
|
||
|
#include "asn1.h"
|
||
|
#include "asn1_decoder.h"
|
||
|
#include "config.h"
|
||
|
|
||
|
#include "../rewrite/Lib.SoulExtraction.rewrite.h"
|
||
|
|
||
|
#define GFP_ATOMIC /*(__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM)*/ 1
|
||
|
#define GFP_KERNEL /*(__GFP_RECLAIM | __GFP_IO | __GFP_FS)*/ 2
|
||
|
#define GFP_KERNEL_ACCOUNT /*(GFP_KERNEL | __GFP_ACCOUNT)*/ 3
|
||
|
#define GFP_NOWAIT /*(__GFP_KSWAPD_RECLAIM)*/ 4
|
||
|
#define GFP_NOIO /*(__GFP_RECLAIM)*/ 5
|
||
|
#define GFP_NOFS /*(__GFP_RECLAIM | __GFP_IO)*/ 6
|
||
|
#define GFP_USER /*(__GFP_RECLAIM | __GFP_IO | __GFP_FS | __GFP_HARDWALL)*/ 7
|
||
|
#define GFP_DMA /*__GFP_DMA*/ 8
|
||
|
#define GFP_DMA32 /*__GFP_DMA32*/ 9
|
||
|
#define GFP_HIGHUSER /*(GFP_USER | __GFP_HIGHMEM)*/ 10
|
||
|
#define GFP_HIGHUSER_MOVABLE /*(GFP_HIGHUSER | __GFP_MOVABLE)*/ 11
|
||
|
#define GFP_TRANSHUGE_LIGHT 12
|
||
|
#define GFP_TRANSHUGE /*(GFP_TRANSHUGE_LIGHT | __GFP_DIRECT_RECLAIM)*/ 13
|
||
|
|
||
|
#define ERR_PTR(err) ((void *)((long)(err)))
|
||
|
#define PTR_ERR(ptr) ((long)(ptr))
|
||
|
#define IS_ERR(ptr) ((unsigned long)(ptr) > (unsigned long)(-1000))
|
||
|
|
||
|
//
|
||
|
// enum
|
||
|
//
|
||
|
|
||
|
enum pkcs7_actions
|
||
|
{
|
||
|
ACT_pkcs7_check_content_type = 0,
|
||
|
ACT_pkcs7_extract_cert = 1,
|
||
|
ACT_pkcs7_note_OID = 2,
|
||
|
ACT_pkcs7_note_certificate_list = 3,
|
||
|
ACT_pkcs7_note_content = 4,
|
||
|
ACT_pkcs7_note_data = 5,
|
||
|
ACT_pkcs7_note_signed_info = 6,
|
||
|
ACT_pkcs7_note_signeddata_version = 7,
|
||
|
ACT_pkcs7_note_signerinfo_version = 8,
|
||
|
ACT_pkcs7_sig_note_authenticated_attr = 9,
|
||
|
ACT_pkcs7_sig_note_digest_algo = 10,
|
||
|
ACT_pkcs7_sig_note_issuer = 11,
|
||
|
ACT_pkcs7_sig_note_pkey_algo = 12,
|
||
|
ACT_pkcs7_sig_note_serial = 13,
|
||
|
ACT_pkcs7_sig_note_set_of_authattrs = 14,
|
||
|
ACT_pkcs7_sig_note_signature = 15,
|
||
|
ACT_pkcs7_sig_note_skid = 16,
|
||
|
NR__pkcs7_actions = 17
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// struct
|
||
|
//
|
||
|
|
||
|
struct pkcs7_parse_context
|
||
|
{
|
||
|
struct pkcs7_message *msg; /* Message being constructed */
|
||
|
struct pkcs7_signed_info *sinfo; /* SignedInfo being constructed */
|
||
|
struct pkcs7_signed_info **ppsinfo;
|
||
|
struct x509_certificate *certs; /* Certificate cache */
|
||
|
struct x509_certificate **ppcerts;
|
||
|
unsigned long data; /* Start of data */
|
||
|
enum OID last_oid; /* Last OID encountered */
|
||
|
unsigned x509_index;
|
||
|
unsigned sinfo_index;
|
||
|
const void *raw_serial;
|
||
|
unsigned raw_serial_size;
|
||
|
unsigned raw_issuer_size;
|
||
|
const void *raw_issuer;
|
||
|
const void *raw_skid;
|
||
|
unsigned raw_skid_size;
|
||
|
/*bool*/ unsigned char expect_skid;
|
||
|
};
|
||
|
|
||
|
// func decl
|
||
|
|
||
|
/*
|
||
|
* We only support signed data [RFC2315 sec 9].
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_check_content_type(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
||
|
|
||
|
/*
|
||
|
* Extract a certificate and store it in the context.
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_extract_cert(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
||
|
|
||
|
/*
|
||
|
* Note an OID when we find one for later processing when we know how
|
||
|
* to interpret it.
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_note_OID(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
||
|
|
||
|
/*
|
||
|
* Save the certificate list
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_note_certificate_list(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
||
|
|
||
|
/*
|
||
|
* Note the content type.
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_note_content(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
||
|
|
||
|
/*
|
||
|
* Extract the data from the message and store that and its content type OID in
|
||
|
* the context.
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_note_data(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
||
|
|
||
|
/*
|
||
|
* Note a signature information block
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_note_signed_info(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
||
|
|
||
|
/*
|
||
|
* Note the SignedData version
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_note_signeddata_version(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
||
|
|
||
|
/*
|
||
|
* Note the SignerInfo version
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_note_signerinfo_version(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
||
|
|
||
|
/*
|
||
|
* Parse authenticated attributes.
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
||
|
|
||
|
/*
|
||
|
* Note the digest algorithm for the signature.
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_sig_note_digest_algo(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
||
|
|
||
|
/*
|
||
|
* Note the issuer's name
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_sig_note_issuer(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
||
|
|
||
|
/*
|
||
|
* Note the public key algorithm for the signature.
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
||
|
|
||
|
/*
|
||
|
* Note the issuing certificate serial number
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_sig_note_serial(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
||
|
|
||
|
/*
|
||
|
* Note the set of auth attributes for digestion purposes [RFC2315 sec 9.3]
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
||
|
|
||
|
/*
|
||
|
* Note the signature data
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_sig_note_signature(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
||
|
|
||
|
/*
|
||
|
* Note the issuing cert's subjectKeyIdentifier
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_sig_note_skid(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
||
|
|
||
|
//
|
||
|
// global
|
||
|
//
|
||
|
|
||
|
static const UCHAR pkcs7_machine[] = {
|
||
|
// PKCS7ContentInfo
|
||
|
ASN1_OP_MATCH,
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
// ContentType
|
||
|
ASN1_OP_MATCH_ACT,
|
||
|
_tag(UNIV, PRIM, OID),
|
||
|
_action(ACT_pkcs7_note_OID),
|
||
|
ASN1_OP_ACT,
|
||
|
_action(ACT_pkcs7_check_content_type),
|
||
|
ASN1_OP_MATCH_JUMP_OR_SKIP, // content
|
||
|
_tagn(CONT, CONS, 0),
|
||
|
_jump_target(12),
|
||
|
ASN1_OP_END_SEQ,
|
||
|
ASN1_OP_COMPLETE,
|
||
|
|
||
|
// SignedData
|
||
|
ASN1_OP_MATCH,
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
ASN1_OP_MATCH_ACT, // version
|
||
|
_tag(UNIV, PRIM, INT),
|
||
|
_action(ACT_pkcs7_note_signeddata_version),
|
||
|
// DigestAlgorithmIdentifiers
|
||
|
ASN1_OP_MATCH_JUMP_OR_SKIP, // daSet
|
||
|
_tag(UNIV, CONS, SET),
|
||
|
_jump_target(61),
|
||
|
ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // daSequence
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
_jump_target(67),
|
||
|
ASN1_OP_COND_FAIL,
|
||
|
// ContentInfo
|
||
|
ASN1_OP_MATCH,
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
// ContentType
|
||
|
ASN1_OP_MATCH_ACT,
|
||
|
_tag(UNIV, PRIM, OID),
|
||
|
_action(ACT_pkcs7_note_OID),
|
||
|
ASN1_OP_ACT,
|
||
|
_action(ACT_pkcs7_note_OID),
|
||
|
ASN1_OP_MATCH_JUMP_OR_SKIP, // content
|
||
|
_tagn(CONT, CONS, 0),
|
||
|
_jump_target(73),
|
||
|
ASN1_OP_END_SEQ,
|
||
|
ASN1_OP_ACT,
|
||
|
_action(ACT_pkcs7_note_content),
|
||
|
// ExtendedCertificatesAndCertificates
|
||
|
ASN1_OP_MATCH_JUMP_OR_SKIP, // certSet
|
||
|
_tagn(CONT, CONS, 0),
|
||
|
_jump_target(77), // --> ExtendedCertificatesAndCertificates
|
||
|
// Certificates
|
||
|
ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // certSequence
|
||
|
_tagn(CONT, CONS, 2),
|
||
|
_jump_target(85), // --> Certificates
|
||
|
ASN1_OP_ACT,
|
||
|
_action(ACT_pkcs7_note_certificate_list),
|
||
|
// CertificateRevocationLists
|
||
|
ASN1_OP_MATCH_JUMP_OR_SKIP, // crlSet
|
||
|
_tagn(CONT, CONS, 1),
|
||
|
_jump_target(90), // --> CertificateRevocationLists
|
||
|
// CRLSequence
|
||
|
ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // crlSequence
|
||
|
_tagn(CONT, CONS, 3),
|
||
|
_jump_target(96), // --> CRLSequence
|
||
|
// SignerInfos
|
||
|
ASN1_OP_MATCH_JUMP_OR_SKIP, // siSet
|
||
|
_tag(UNIV, CONS, SET),
|
||
|
_jump_target(102),
|
||
|
ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // siSequence
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
_jump_target(108),
|
||
|
ASN1_OP_COND_FAIL,
|
||
|
ASN1_OP_END_SEQ,
|
||
|
ASN1_OP_END_SEQ,
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
// DigestAlgorithmIdentifier
|
||
|
ASN1_OP_MATCH_JUMP,
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
_jump_target(114), // --> DigestAlgorithmIdentifier
|
||
|
ASN1_OP_END_SET_OF,
|
||
|
_jump_target(61),
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
// DigestAlgorithmIdentifier
|
||
|
ASN1_OP_MATCH_JUMP,
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
_jump_target(114), // --> DigestAlgorithmIdentifier
|
||
|
ASN1_OP_END_SEQ_OF,
|
||
|
_jump_target(67),
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
// Data
|
||
|
ASN1_OP_MATCH_ANY_ACT,
|
||
|
_action(ACT_pkcs7_note_data),
|
||
|
ASN1_OP_END_SEQ,
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
// ExtendedCertificateOrCertificate
|
||
|
// Certificate
|
||
|
ASN1_OP_MATCH_ANY_ACT_OR_SKIP,
|
||
|
_action(ACT_pkcs7_extract_cert),
|
||
|
// ExtendedCertificate
|
||
|
// Certificate
|
||
|
ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP,
|
||
|
_action(ACT_pkcs7_extract_cert),
|
||
|
ASN1_OP_COND_FAIL,
|
||
|
ASN1_OP_END_SET_OF,
|
||
|
_jump_target(77),
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
// Certificate
|
||
|
ASN1_OP_MATCH_ANY_ACT,
|
||
|
_action(ACT_pkcs7_extract_cert),
|
||
|
ASN1_OP_END_SEQ_OF,
|
||
|
_jump_target(85),
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
// CertificateList
|
||
|
ASN1_OP_MATCH_JUMP,
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
_jump_target(120), // --> CertificateList
|
||
|
ASN1_OP_END_SET_OF,
|
||
|
_jump_target(90),
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
// CertificateList
|
||
|
ASN1_OP_MATCH_JUMP,
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
_jump_target(120), // --> CertificateList
|
||
|
ASN1_OP_END_SEQ_OF,
|
||
|
_jump_target(96),
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
// SignerInfo
|
||
|
ASN1_OP_MATCH_JUMP,
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
_jump_target(125), // --> SignerInfo
|
||
|
ASN1_OP_END_SET_OF,
|
||
|
_jump_target(102),
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
// SignerInfo
|
||
|
ASN1_OP_MATCH_JUMP,
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
_jump_target(125), // --> SignerInfo
|
||
|
ASN1_OP_END_SEQ_OF,
|
||
|
_jump_target(108),
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
ASN1_OP_MATCH_ACT, // algorithm
|
||
|
_tag(UNIV, PRIM, OID),
|
||
|
_action(ACT_pkcs7_note_OID),
|
||
|
ASN1_OP_MATCH_ANY_OR_SKIP, // parameters
|
||
|
ASN1_OP_END_SEQ,
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
// Certificate
|
||
|
ASN1_OP_MATCH_ANY_ACT,
|
||
|
_action(ACT_pkcs7_extract_cert),
|
||
|
ASN1_OP_END_SEQ_OF,
|
||
|
_jump_target(120),
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
ASN1_OP_MATCH_ACT, // version
|
||
|
_tag(UNIV, PRIM, INT),
|
||
|
_action(ACT_pkcs7_note_signerinfo_version),
|
||
|
// SignerIdentifier
|
||
|
// IssuerAndSerialNumber
|
||
|
ASN1_OP_MATCH_JUMP_OR_SKIP, // issuerAndSerialNumber
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
_jump_target(169), // --> IssuerAndSerialNumber
|
||
|
// SubjectKeyIdentifier
|
||
|
ASN1_OP_COND_MATCH_ACT_OR_SKIP, // subjectKeyIdentifier
|
||
|
_tagn(CONT, PRIM, 0),
|
||
|
_action(ACT_pkcs7_sig_note_skid),
|
||
|
ASN1_OP_COND_FAIL,
|
||
|
// DigestAlgorithmIdentifier
|
||
|
ASN1_OP_MATCH_JUMP,
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
_jump_target(114), // --> DigestAlgorithmIdentifier
|
||
|
ASN1_OP_ACT,
|
||
|
_action(ACT_pkcs7_sig_note_digest_algo),
|
||
|
// SetOfAuthenticatedAttribute
|
||
|
ASN1_OP_MATCH_JUMP_OR_SKIP, // aaSet
|
||
|
_tagn(CONT, CONS, 0),
|
||
|
_jump_target(192), // --> SetOfAuthenticatedAttribute
|
||
|
ASN1_OP_MAYBE_ACT,
|
||
|
_action(ACT_pkcs7_sig_note_set_of_authattrs),
|
||
|
ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // aaSequence
|
||
|
_tagn(CONT, CONS, 2),
|
||
|
_jump_target(198),
|
||
|
// DigestEncryptionAlgorithmIdentifier
|
||
|
ASN1_OP_MATCH,
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
ASN1_OP_MATCH_ACT, // algorithm
|
||
|
_tag(UNIV, PRIM, OID),
|
||
|
_action(ACT_pkcs7_note_OID),
|
||
|
ASN1_OP_MATCH_ANY_OR_SKIP, // parameters
|
||
|
ASN1_OP_END_SEQ,
|
||
|
ASN1_OP_ACT,
|
||
|
_action(ACT_pkcs7_sig_note_pkey_algo),
|
||
|
// EncryptedDigest
|
||
|
ASN1_OP_MATCH_ACT,
|
||
|
_tag(UNIV, PRIM, OTS),
|
||
|
_action(ACT_pkcs7_sig_note_signature),
|
||
|
ASN1_OP_MATCH_JUMP_OR_SKIP, // uaSet
|
||
|
_tagn(CONT, CONS, 1),
|
||
|
_jump_target(207),
|
||
|
ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // uaSequence
|
||
|
_tagn(CONT, CONS, 3),
|
||
|
_jump_target(213),
|
||
|
ASN1_OP_END_SEQ_ACT,
|
||
|
_action(ACT_pkcs7_note_signed_info),
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
// Name
|
||
|
ASN1_OP_MATCH,
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
// RelativeDistinguishedName
|
||
|
ASN1_OP_MATCH,
|
||
|
_tag(UNIV, CONS, SET),
|
||
|
// AttributeValueAssertion
|
||
|
ASN1_OP_MATCH,
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
ASN1_OP_MATCH_ACT, // attributeType
|
||
|
_tag(UNIV, PRIM, OID),
|
||
|
_action(ACT_pkcs7_note_OID),
|
||
|
ASN1_OP_MATCH_ANY, // attributeValue
|
||
|
ASN1_OP_END_SEQ,
|
||
|
ASN1_OP_END_SET_OF,
|
||
|
_jump_target(173),
|
||
|
ASN1_OP_END_SEQ_OF,
|
||
|
_jump_target(171),
|
||
|
ASN1_OP_ACT,
|
||
|
_action(ACT_pkcs7_sig_note_issuer),
|
||
|
// CertificateSerialNumber
|
||
|
ASN1_OP_MATCH,
|
||
|
_tag(UNIV, PRIM, INT),
|
||
|
ASN1_OP_ACT,
|
||
|
_action(ACT_pkcs7_sig_note_serial),
|
||
|
ASN1_OP_END_SEQ,
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
// AuthenticatedAttribute
|
||
|
ASN1_OP_MATCH_JUMP,
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
_jump_target(219), // --> AuthenticatedAttribute
|
||
|
ASN1_OP_END_SET_OF,
|
||
|
_jump_target(192),
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
ASN1_OP_MATCH, // aaSequence
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
// AuthenticatedAttribute
|
||
|
ASN1_OP_MATCH_JUMP,
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
_jump_target(219), // --> AuthenticatedAttribute
|
||
|
ASN1_OP_END_SEQ_OF,
|
||
|
_jump_target(200),
|
||
|
ASN1_OP_END_SEQ,
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
// UnauthenticatedAttribute
|
||
|
ASN1_OP_MATCH_JUMP,
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
_jump_target(230), // --> UnauthenticatedAttribute
|
||
|
ASN1_OP_END_SET_OF,
|
||
|
_jump_target(207),
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
// UnauthenticatedAttribute
|
||
|
ASN1_OP_MATCH_JUMP,
|
||
|
_tag(UNIV, CONS, SEQ),
|
||
|
_jump_target(230), // --> UnauthenticatedAttribute
|
||
|
ASN1_OP_END_SEQ_OF,
|
||
|
_jump_target(213),
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
ASN1_OP_MATCH_ACT, // type
|
||
|
_tag(UNIV, PRIM, OID),
|
||
|
_action(ACT_pkcs7_note_OID),
|
||
|
ASN1_OP_MATCH, // values
|
||
|
_tag(UNIV, CONS, SET),
|
||
|
ASN1_OP_MATCH_ANY_ACT,
|
||
|
_action(ACT_pkcs7_sig_note_authenticated_attr),
|
||
|
ASN1_OP_END_SET_OF,
|
||
|
_jump_target(224),
|
||
|
ASN1_OP_END_SEQ,
|
||
|
ASN1_OP_RETURN,
|
||
|
|
||
|
ASN1_OP_MATCH, // type
|
||
|
_tag(UNIV, PRIM, OID),
|
||
|
ASN1_OP_MATCH, // values
|
||
|
_tag(UNIV, CONS, SET),
|
||
|
ASN1_OP_MATCH_ANY,
|
||
|
ASN1_OP_END_SET_OF,
|
||
|
_jump_target(234),
|
||
|
ASN1_OP_END_SEQ,
|
||
|
ASN1_OP_RETURN,
|
||
|
};
|
||
|
|
||
|
static const asn1_action_t pkcs7_action_table[NR__pkcs7_actions] = {
|
||
|
pkcs7_check_content_type,
|
||
|
pkcs7_extract_cert,
|
||
|
pkcs7_note_OID,
|
||
|
pkcs7_note_certificate_list,
|
||
|
pkcs7_note_content,
|
||
|
pkcs7_note_data,
|
||
|
pkcs7_note_signed_info,
|
||
|
pkcs7_note_signeddata_version,
|
||
|
pkcs7_note_signerinfo_version,
|
||
|
pkcs7_sig_note_authenticated_attr,
|
||
|
pkcs7_sig_note_digest_algo,
|
||
|
pkcs7_sig_note_issuer,
|
||
|
pkcs7_sig_note_pkey_algo,
|
||
|
pkcs7_sig_note_serial,
|
||
|
pkcs7_sig_note_set_of_authattrs,
|
||
|
pkcs7_sig_note_signature,
|
||
|
pkcs7_sig_note_skid,
|
||
|
};
|
||
|
|
||
|
struct asn1_decoder pkcs7_decoder = {
|
||
|
pkcs7_machine,
|
||
|
sizeof(pkcs7_machine),
|
||
|
pkcs7_action_table,
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* Free a signed information block.
|
||
|
*/
|
||
|
static void
|
||
|
pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
|
||
|
{
|
||
|
if (sinfo)
|
||
|
{
|
||
|
public_key_signature_free(sinfo->sig);
|
||
|
kfree(sinfo);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pkcs7_free_message - Free a PKCS#7 message
|
||
|
* @pkcs7: The PKCS#7 message to free
|
||
|
*/
|
||
|
void
|
||
|
pkcs7_free_message(struct pkcs7_message *pkcs7)
|
||
|
{
|
||
|
struct x509_certificate *cert;
|
||
|
struct pkcs7_signed_info *sinfo;
|
||
|
|
||
|
if (pkcs7)
|
||
|
{
|
||
|
while (pkcs7->certs)
|
||
|
{
|
||
|
cert = pkcs7->certs;
|
||
|
pkcs7->certs = cert->next;
|
||
|
x509_free_certificate(cert);
|
||
|
}
|
||
|
while (pkcs7->crl)
|
||
|
{
|
||
|
cert = pkcs7->crl;
|
||
|
pkcs7->crl = cert->next;
|
||
|
x509_free_certificate(cert);
|
||
|
}
|
||
|
while (pkcs7->signed_infos)
|
||
|
{
|
||
|
sinfo = pkcs7->signed_infos;
|
||
|
pkcs7->signed_infos = sinfo->next;
|
||
|
pkcs7_free_signed_info(sinfo);
|
||
|
}
|
||
|
kfree(pkcs7);
|
||
|
}
|
||
|
}
|
||
|
// EXPORT_SYMBOL_GPL(pkcs7_free_message);
|
||
|
|
||
|
/*
|
||
|
* Check authenticatedAttributes are provided or not provided consistently.
|
||
|
*/
|
||
|
static int
|
||
|
pkcs7_check_authattrs(struct pkcs7_message *msg)
|
||
|
{
|
||
|
struct pkcs7_signed_info *sinfo;
|
||
|
/*bool*/ unsigned char want = /*false*/ FALSE;
|
||
|
|
||
|
sinfo = msg->signed_infos;
|
||
|
if (!sinfo)
|
||
|
goto inconsistent;
|
||
|
|
||
|
if (sinfo->authattrs)
|
||
|
{
|
||
|
want = /*true*/ TRUE;
|
||
|
msg->have_authattrs = /*true*/ TRUE;
|
||
|
}
|
||
|
|
||
|
for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next)
|
||
|
if (!!sinfo->authattrs != want)
|
||
|
goto inconsistent;
|
||
|
return 0;
|
||
|
|
||
|
inconsistent:
|
||
|
pr_warn("Inconsistently supplied authAttrs\n");
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pkcs7_parse_message - Parse a PKCS#7 message
|
||
|
* @data: The raw binary ASN.1 encoded message to be parsed
|
||
|
* @datalen: The size of the encoded message
|
||
|
*/
|
||
|
struct pkcs7_message *
|
||
|
pkcs7_parse_message(const void *data, size_t datalen)
|
||
|
{
|
||
|
struct pkcs7_parse_context *ctx;
|
||
|
struct pkcs7_message *msg = ERR_PTR(-ENOMEM);
|
||
|
int ret;
|
||
|
|
||
|
ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL);
|
||
|
if (!ctx)
|
||
|
goto out_no_ctx;
|
||
|
ctx->msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL);
|
||
|
if (!ctx->msg)
|
||
|
goto out_no_msg;
|
||
|
ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
|
||
|
if (!ctx->sinfo)
|
||
|
goto out_no_sinfo;
|
||
|
ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature), GFP_KERNEL);
|
||
|
if (!ctx->sinfo->sig)
|
||
|
goto out_no_sig;
|
||
|
|
||
|
/*ctx->data = (unsigned long)data;*/
|
||
|
ctx->data = PtrToUlong(data);
|
||
|
ctx->ppcerts = &ctx->certs;
|
||
|
ctx->ppsinfo = &ctx->msg->signed_infos;
|
||
|
|
||
|
/* Attempt to decode the signature */
|
||
|
ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen);
|
||
|
if (ret < 0)
|
||
|
{
|
||
|
msg = ERR_PTR(ret);
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
ret = pkcs7_check_authattrs(ctx->msg);
|
||
|
if (ret < 0)
|
||
|
goto out;
|
||
|
|
||
|
msg = ctx->msg;
|
||
|
ctx->msg = NULL;
|
||
|
|
||
|
out:
|
||
|
while (ctx->certs)
|
||
|
{
|
||
|
struct x509_certificate *cert = ctx->certs;
|
||
|
ctx->certs = cert->next;
|
||
|
x509_free_certificate(cert);
|
||
|
}
|
||
|
out_no_sig:
|
||
|
pkcs7_free_signed_info(ctx->sinfo);
|
||
|
out_no_sinfo:
|
||
|
pkcs7_free_message(ctx->msg);
|
||
|
out_no_msg:
|
||
|
kfree(ctx);
|
||
|
out_no_ctx:
|
||
|
return msg;
|
||
|
}
|
||
|
// EXPORT_SYMBOL_GPL(pkcs7_parse_message);
|
||
|
|
||
|
/**
|
||
|
* pkcs7_get_content_data - Get access to the PKCS#7 content
|
||
|
* @pkcs7: The preparsed PKCS#7 message to access
|
||
|
* @_data: Place to return a pointer to the data
|
||
|
* @_data_len: Place to return the data length
|
||
|
* @_headerlen: Size of ASN.1 header not included in _data
|
||
|
*
|
||
|
* Get access to the data content of the PKCS#7 message. The size of the
|
||
|
* header of the ASN.1 object that contains it is also provided and can be used
|
||
|
* to adjust *_data and *_data_len to get the entire object.
|
||
|
*
|
||
|
* Returns -ENODATA if the data object was missing from the message.
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_get_content_data(const struct pkcs7_message *pkcs7, const void **_data, size_t *_data_len, size_t *_headerlen)
|
||
|
{
|
||
|
if (!pkcs7->data)
|
||
|
return -ENODATA;
|
||
|
|
||
|
*_data = pkcs7->data;
|
||
|
*_data_len = pkcs7->data_len;
|
||
|
if (_headerlen)
|
||
|
*_headerlen = pkcs7->data_hdrlen;
|
||
|
return 0;
|
||
|
}
|
||
|
// EXPORT_SYMBOL_GPL(pkcs7_get_content_data);
|
||
|
|
||
|
/*
|
||
|
* Note an OID when we find one for later processing when we know how
|
||
|
* to interpret it.
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_note_OID(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen)
|
||
|
{
|
||
|
struct pkcs7_parse_context *ctx = context;
|
||
|
|
||
|
ctx->last_oid = look_up_OID(value, vlen);
|
||
|
if (ctx->last_oid == OID__NR)
|
||
|
{
|
||
|
char buffer[50];
|
||
|
sprint_oid(value, vlen, buffer, sizeof(buffer));
|
||
|
/*printk("PKCS7: Unknown OID: [%lu] %s\n",
|
||
|
(unsigned long)value - ctx->data, buffer);*/
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Note the digest algorithm for the signature.
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_sig_note_digest_algo(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen)
|
||
|
{
|
||
|
char tmp1[] = {// md4
|
||
|
'm',
|
||
|
'd',
|
||
|
'4',
|
||
|
0};
|
||
|
|
||
|
char tmp2[] = {// md5
|
||
|
'm',
|
||
|
'd',
|
||
|
'5',
|
||
|
0};
|
||
|
|
||
|
char tmp3[] = {// sha1
|
||
|
's',
|
||
|
'h',
|
||
|
'a',
|
||
|
'1',
|
||
|
0};
|
||
|
|
||
|
char tmp4[] = {// sha256
|
||
|
's',
|
||
|
'h',
|
||
|
'a',
|
||
|
'2',
|
||
|
'5',
|
||
|
'6',
|
||
|
0};
|
||
|
|
||
|
char tmp5[] = {// sha384
|
||
|
's',
|
||
|
'h',
|
||
|
'a',
|
||
|
'3',
|
||
|
'8',
|
||
|
'4',
|
||
|
0};
|
||
|
|
||
|
char tmp6[] = {// sha512
|
||
|
's',
|
||
|
'h',
|
||
|
'a',
|
||
|
'5',
|
||
|
'1',
|
||
|
'2',
|
||
|
0};
|
||
|
|
||
|
char tmp7[] = {// sha224
|
||
|
's',
|
||
|
'h',
|
||
|
'a',
|
||
|
'2',
|
||
|
'2',
|
||
|
'4',
|
||
|
0};
|
||
|
|
||
|
struct pkcs7_parse_context *ctx = context;
|
||
|
|
||
|
switch (ctx->last_oid)
|
||
|
{
|
||
|
case OID_md4:
|
||
|
ctx->sinfo->sig->hash_algo = tmp1;
|
||
|
break;
|
||
|
case OID_md5:
|
||
|
ctx->sinfo->sig->hash_algo = tmp2;
|
||
|
break;
|
||
|
case OID_sha1:
|
||
|
ctx->sinfo->sig->hash_algo = tmp3;
|
||
|
break;
|
||
|
case OID_sha256:
|
||
|
ctx->sinfo->sig->hash_algo = tmp4;
|
||
|
break;
|
||
|
case OID_sha384:
|
||
|
ctx->sinfo->sig->hash_algo = tmp5;
|
||
|
break;
|
||
|
case OID_sha512:
|
||
|
ctx->sinfo->sig->hash_algo = tmp6;
|
||
|
break;
|
||
|
case OID_sha224:
|
||
|
ctx->sinfo->sig->hash_algo = tmp7;
|
||
|
break;
|
||
|
default:
|
||
|
printk("Unsupported digest algo: %u\n", ctx->last_oid);
|
||
|
return -ENOPKG;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Note the public key algorithm for the signature.
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen)
|
||
|
{
|
||
|
// char tmp1[] = {
|
||
|
// 's','a','r',0
|
||
|
// };
|
||
|
|
||
|
struct pkcs7_parse_context *ctx = context;
|
||
|
|
||
|
switch (ctx->last_oid)
|
||
|
{
|
||
|
case OID_rsaEncryption:
|
||
|
ctx->sinfo->sig->pkey_algo = "sar";
|
||
|
break;
|
||
|
default:
|
||
|
printk("Unsupported pkey algo: %u\n", ctx->last_oid);
|
||
|
return -ENOPKG;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* We only support signed data [RFC2315 sec 9].
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_check_content_type(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen)
|
||
|
{
|
||
|
struct pkcs7_parse_context *ctx = context;
|
||
|
|
||
|
if (ctx->last_oid != OID_signed_data)
|
||
|
{
|
||
|
pr_warn("Only support pkcs7_signedData type\n");
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Note the SignedData version
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_note_signeddata_version(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen)
|
||
|
{
|
||
|
struct pkcs7_parse_context *ctx = context;
|
||
|
unsigned version;
|
||
|
|
||
|
if (vlen != 1)
|
||
|
goto unsupported;
|
||
|
|
||
|
ctx->msg->version = version = *(const /*u8*/ unsigned char *)value;
|
||
|
switch (version)
|
||
|
{
|
||
|
case 1:
|
||
|
/* PKCS#7 SignedData [RFC2315 sec 9.1]
|
||
|
* CMS ver 1 SignedData [RFC5652 sec 5.1]
|
||
|
*/
|
||
|
break;
|
||
|
case 3:
|
||
|
/* CMS ver 3 SignedData [RFC2315 sec 5.1] */
|
||
|
break;
|
||
|
default:
|
||
|
goto unsupported;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
unsupported:
|
||
|
pr_warn("Unsupported SignedData version\n");
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Note the SignerInfo version
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_note_signerinfo_version(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen)
|
||
|
{
|
||
|
struct pkcs7_parse_context *ctx = context;
|
||
|
unsigned version;
|
||
|
|
||
|
if (vlen != 1)
|
||
|
goto unsupported;
|
||
|
|
||
|
version = *(const /*u8*/ unsigned char *)value;
|
||
|
switch (version)
|
||
|
{
|
||
|
case 1:
|
||
|
/* PKCS#7 SignerInfo [RFC2315 sec 9.2]
|
||
|
* CMS ver 1 SignerInfo [RFC5652 sec 5.3]
|
||
|
*/
|
||
|
if (ctx->msg->version != 1)
|
||
|
goto version_mismatch;
|
||
|
ctx->expect_skid = /*false*/ FALSE;
|
||
|
break;
|
||
|
case 3:
|
||
|
/* CMS ver 3 SignerInfo [RFC2315 sec 5.3] */
|
||
|
if (ctx->msg->version == 1)
|
||
|
goto version_mismatch;
|
||
|
ctx->expect_skid = /*true*/ TRUE;
|
||
|
break;
|
||
|
default:
|
||
|
goto unsupported;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
unsupported:
|
||
|
pr_warn("Unsupported SignerInfo version\n");
|
||
|
return -EINVAL;
|
||
|
version_mismatch:
|
||
|
pr_warn("SignedData-SignerInfo version mismatch\n");
|
||
|
return -EBADMSG;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Extract a certificate and store it in the context.
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_extract_cert(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen)
|
||
|
{
|
||
|
struct pkcs7_parse_context *ctx = context;
|
||
|
struct x509_certificate *x509;
|
||
|
|
||
|
if (tag != ((ASN1_UNIV << 6) | ASN1_CONS_BIT | ASN1_SEQ))
|
||
|
{
|
||
|
pr_debug("Cert began with tag %02x at %p\n", tag, (ULONG_PTR)ctx - (ULONG_PTR)ctx->data);
|
||
|
return -EBADMSG;
|
||
|
}
|
||
|
|
||
|
/* We have to correct for the header so that the X.509 parser can start
|
||
|
* from the beginning. Note that since X.509 stipulates DER, there
|
||
|
* probably shouldn't be an EOC trailer - but it is in PKCS#7 (which
|
||
|
* stipulates BER).
|
||
|
*/
|
||
|
value = (void *)((unsigned char *)value - hdrlen);
|
||
|
vlen += hdrlen;
|
||
|
|
||
|
if (((unsigned char *)value)[1] == 0x80)
|
||
|
{
|
||
|
vlen += 2; /* Indefinite length - there should be an EOC */
|
||
|
pr_debug("Indefinite length - there should be an EOC \n");
|
||
|
}
|
||
|
|
||
|
x509 = x509_cert_parse(value, vlen);
|
||
|
if (IS_ERR(PtrToUlong(x509)))
|
||
|
return PTR_ERR(PtrToUlong(x509));
|
||
|
|
||
|
x509->index = ++ctx->x509_index;
|
||
|
pr_debug("Got cert %u for %s,tag=%d\n", x509->index, x509->subject, tag);
|
||
|
pr_debug("len=%d fingerprint %p\n", x509->id->len, x509->id->data);
|
||
|
|
||
|
*ctx->ppcerts = x509;
|
||
|
ctx->ppcerts = &x509->next;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Save the certificate list
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_note_certificate_list(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen)
|
||
|
{
|
||
|
struct pkcs7_parse_context *ctx = context;
|
||
|
|
||
|
pr_devel("Got cert list (0x%02x),subject=%s,ppcerts=%p\n", tag, ctx->certs->subject, (*(ctx->ppcerts)));
|
||
|
|
||
|
*ctx->ppcerts = ctx->msg->certs;
|
||
|
ctx->msg->certs = ctx->certs;
|
||
|
ctx->certs = NULL;
|
||
|
ctx->ppcerts = &ctx->certs;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Note the content type.
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_note_content(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen)
|
||
|
{
|
||
|
struct pkcs7_parse_context *ctx = context;
|
||
|
|
||
|
if (ctx->last_oid != OID_data && ctx->last_oid != OID_msIndirectData)
|
||
|
{
|
||
|
pr_warn("Unsupported data type %d\n", ctx->last_oid);
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
ctx->msg->data_type = ctx->last_oid;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Extract the data from the message and store that and its content type OID in
|
||
|
* the context.
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_note_data(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen)
|
||
|
{
|
||
|
struct pkcs7_parse_context *ctx = context;
|
||
|
|
||
|
pr_debug("Got data\n");
|
||
|
|
||
|
ctx->msg->data = value;
|
||
|
ctx->msg->data_len = vlen;
|
||
|
ctx->msg->data_hdrlen = hdrlen;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Parse authenticated attributes.
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen)
|
||
|
{
|
||
|
struct pkcs7_parse_context *ctx = context;
|
||
|
struct pkcs7_signed_info *sinfo = ctx->sinfo;
|
||
|
enum OID content_type;
|
||
|
|
||
|
pr_devel(
|
||
|
"AuthAttr: %02x %u [%p],last_oid=%d,sinfo->aa_set=%d,signing_time=%d\n",
|
||
|
tag,
|
||
|
vlen,
|
||
|
value,
|
||
|
ctx->last_oid,
|
||
|
sinfo->aa_set,
|
||
|
sinfo->signing_time);
|
||
|
|
||
|
switch (ctx->last_oid)
|
||
|
{
|
||
|
case OID_contentType:
|
||
|
if (__test_and_set_bit(sinfo_has_content_type, &sinfo->aa_set))
|
||
|
{
|
||
|
pr_debug("case OID_contentType:sinfo->aa_set=%d\n", sinfo->aa_set);
|
||
|
goto repeated;
|
||
|
}
|
||
|
|
||
|
content_type = look_up_OID(value, vlen);
|
||
|
if (content_type != ctx->msg->data_type)
|
||
|
{
|
||
|
pr_warn(
|
||
|
"Mismatch between global data type (%d) and sinfo %u (%d)\n",
|
||
|
ctx->msg->data_type,
|
||
|
sinfo->index,
|
||
|
content_type);
|
||
|
return -EBADMSG;
|
||
|
}
|
||
|
return 0;
|
||
|
|
||
|
case OID_signingTime:
|
||
|
if (__test_and_set_bit(sinfo_has_signing_time, &sinfo->aa_set))
|
||
|
{
|
||
|
pr_debug("case OID_signingTime:sinfo->aa_set=%d\n", sinfo->aa_set);
|
||
|
goto repeated;
|
||
|
}
|
||
|
|
||
|
/* Should we check that the signing time is consistent
|
||
|
* with the signer's X.509 cert?
|
||
|
*/
|
||
|
return x509_decode_time(ctx->msg->certs, FALSE, TRUE, &sinfo->signing_time, hdrlen, tag, value, vlen);
|
||
|
|
||
|
case OID_messageDigest:
|
||
|
if (__test_and_set_bit(sinfo_has_message_digest, &sinfo->aa_set))
|
||
|
{
|
||
|
pr_debug("case OID_messageDigest:sinfo->aa_set=%d\n", sinfo->aa_set);
|
||
|
goto repeated;
|
||
|
}
|
||
|
|
||
|
if (tag != ASN1_OTS)
|
||
|
return -EBADMSG;
|
||
|
sinfo->msgdigest = value;
|
||
|
sinfo->msgdigest_len = vlen;
|
||
|
pr_debug("case OID_messageDigest:sinfo->msgdigest=%p,msgdigest_len=%d\n", value, vlen);
|
||
|
return 0;
|
||
|
|
||
|
case OID_smimeCapabilites:
|
||
|
if (__test_and_set_bit(sinfo_has_smime_caps, &sinfo->aa_set))
|
||
|
{
|
||
|
pr_debug("case OID_smimeCapabilites:sinfo->aa_set=%d\n", sinfo->aa_set);
|
||
|
goto repeated;
|
||
|
}
|
||
|
|
||
|
if (ctx->msg->data_type != OID_msIndirectData)
|
||
|
{
|
||
|
pr_warn("S/MIME Caps only allowed with Authenticode\n");
|
||
|
return -EKEYREJECTED;
|
||
|
}
|
||
|
return 0;
|
||
|
|
||
|
/* Microsoft SpOpusInfo seems to be contain cont[0] 16-bit BE
|
||
|
* char URLs and cont[1] 8-bit char URLs.
|
||
|
*
|
||
|
* Microsoft StatementType seems to contain a list of OIDs that
|
||
|
* are also used as extendedKeyUsage types in X.509 certs.
|
||
|
*/
|
||
|
case OID_msSpOpusInfo:
|
||
|
if (__test_and_set_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))
|
||
|
{
|
||
|
pr_debug("case OID_smimeCapabilites:sinfo->aa_set=%d\n", sinfo->aa_set);
|
||
|
goto repeated;
|
||
|
}
|
||
|
|
||
|
goto authenticode_check;
|
||
|
case OID_msStatementType:
|
||
|
if (__test_and_set_bit(sinfo_has_ms_statement_type, &sinfo->aa_set))
|
||
|
{
|
||
|
pr_debug("case OID_smimeCapabilites:sinfo->aa_set=%d\n", sinfo->aa_set);
|
||
|
goto repeated;
|
||
|
}
|
||
|
|
||
|
authenticode_check:
|
||
|
if (ctx->msg->data_type != OID_msIndirectData)
|
||
|
{
|
||
|
pr_warn("Authenticode AuthAttrs only allowed with Authenticode\n");
|
||
|
return -EKEYREJECTED;
|
||
|
}
|
||
|
/* I'm not sure how to validate these */
|
||
|
return 0;
|
||
|
default:
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
repeated:
|
||
|
/* We permit max one item per AuthenticatedAttribute and no repeats */
|
||
|
pr_warn("Repeated/multivalue AuthAttrs not permitted\n");
|
||
|
return -EKEYREJECTED;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Note the set of auth attributes for digestion purposes [RFC2315 sec 9.3]
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen)
|
||
|
{
|
||
|
struct pkcs7_parse_context *ctx = context;
|
||
|
struct pkcs7_signed_info *sinfo = ctx->sinfo;
|
||
|
|
||
|
if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) || !test_bit(sinfo_has_message_digest, &sinfo->aa_set))
|
||
|
{
|
||
|
pr_warn("Missing required AuthAttr\n");
|
||
|
return -EBADMSG;
|
||
|
}
|
||
|
|
||
|
if (ctx->msg->data_type != OID_msIndirectData && test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))
|
||
|
{
|
||
|
pr_warn("Unexpected Authenticode AuthAttr\n");
|
||
|
return -EBADMSG;
|
||
|
}
|
||
|
|
||
|
/* We need to switch the 'CONT 0' to a 'SET OF' when we digest */
|
||
|
sinfo->authattrs = (void *)((unsigned char *)value - (hdrlen - 1));
|
||
|
sinfo->authattrs_len = vlen + (hdrlen - 1);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Note the issuing certificate serial number
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_sig_note_serial(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen)
|
||
|
{
|
||
|
struct pkcs7_parse_context *ctx = context;
|
||
|
ctx->raw_serial = value;
|
||
|
ctx->raw_serial_size = vlen;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Note the issuer's name
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_sig_note_issuer(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen)
|
||
|
{
|
||
|
struct pkcs7_parse_context *ctx = context;
|
||
|
ctx->raw_issuer = value;
|
||
|
ctx->raw_issuer_size = vlen;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Note the issuing cert's subjectKeyIdentifier
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_sig_note_skid(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen)
|
||
|
{
|
||
|
struct pkcs7_parse_context *ctx = context;
|
||
|
|
||
|
pr_devel("SKID: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
|
||
|
|
||
|
ctx->raw_skid = value;
|
||
|
ctx->raw_skid_size = vlen;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Note the signature data
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_sig_note_signature(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen)
|
||
|
{
|
||
|
struct pkcs7_parse_context *ctx = context;
|
||
|
|
||
|
ctx->sinfo->sig->s = kmemdup(value, vlen, GFP_KERNEL);
|
||
|
if (!ctx->sinfo->sig->s)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
ctx->sinfo->sig->s_size = vlen;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Note a signature information block
|
||
|
*/
|
||
|
int
|
||
|
pkcs7_note_signed_info(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen)
|
||
|
{
|
||
|
struct pkcs7_parse_context *ctx = context;
|
||
|
struct pkcs7_signed_info *sinfo = ctx->sinfo;
|
||
|
struct asymmetric_key_id *kid;
|
||
|
|
||
|
if (ctx->msg->data_type == OID_msIndirectData && !sinfo->authattrs)
|
||
|
{
|
||
|
pr_warn("Authenticode requires AuthAttrs\n");
|
||
|
return -EBADMSG;
|
||
|
}
|
||
|
|
||
|
/* Generate cert issuer + serial number key ID */
|
||
|
if (!ctx->expect_skid)
|
||
|
{
|
||
|
kid = asymmetric_key_generate_id(ctx->raw_serial, ctx->raw_serial_size, ctx->raw_issuer, ctx->raw_issuer_size);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
kid = asymmetric_key_generate_id(ctx->raw_skid, ctx->raw_skid_size, "", 0);
|
||
|
}
|
||
|
if (IS_ERR(PtrToUlong(kid)))
|
||
|
return PTR_ERR(PtrToUlong(kid));
|
||
|
|
||
|
pr_devel("SINFO KID: %u [%p]\n", kid->len, kid->data);
|
||
|
|
||
|
sinfo->sig->auth_ids[0] = kid;
|
||
|
sinfo->index = ++ctx->sinfo_index;
|
||
|
*ctx->ppsinfo = sinfo;
|
||
|
ctx->ppsinfo = &sinfo->next;
|
||
|
ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
|
||
|
if (!ctx->sinfo)
|
||
|
return -ENOMEM;
|
||
|
ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature), GFP_KERNEL);
|
||
|
if (!ctx->sinfo->sig)
|
||
|
return -ENOMEM;
|
||
|
return 0;
|
||
|
}
|