Ethereal-dev: [Ethereal-dev] Question for packet-ber.c gurus

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Yaniv Kaul <ykaul@xxxxxxxxxxxx>
Date: Sat, 01 May 2004 18:36:27 +0200
I'm trying to add support for dissecting X.509 certificates to Ethereal (which can then be used in IKE, SSL, anything else that uses them).
(I know it's DER, not BER, but still).
I'm having a bit of a trouble with it, I suspect it's due to EXPLICIT tags.
From RFC 3280:
Certificate  ::=  SEQUENCE  {
       tbsCertificate       TBSCertificate,
       signatureAlgorithm   AlgorithmIdentifier,
       signatureValue       BIT STRING  }

  TBSCertificate  ::=  SEQUENCE  {
       version         [0]  EXPLICIT Version DEFAULT v1,
       serialNumber         CertificateSerialNumber,


I tried creating and dissecting it through the following structures:
static ber_sequence Certificate_sequence[] = {
   { BER_CLASS_UNI, BER_UNI_TAG_SEQUENCE, 0, dissect_tbsCertificate },
{ BER_CLASS_UNI, BER_UNI_TAG_INTEGER, 0, dissect_TBSCertificate_serialNumber },
...

and
static ber_sequence TBSCertificate_sequence[1] = {
{ BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_TBSCertificate_version }
};

and it seems to work - up to the point that it does not dissect the serial number - it hops over it.
Any ideas?

Do we have anything special for dissecting EXPLICIT tags?

Attached is my effort thus far.

TIA,
Y.

/* packet-pki.c
 * Dissector for X.509 certs as described in rfc3280, section 4.1
 * Copyright 2004, Yaniv Kaul ykaul@xxxxxxxxxxxx
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxxxxxx>
 * Copyright 1998 Gerald Combs
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif

#include <string.h>

#include <glib.h>
#include <epan/packet.h>

#include "packet-ber.h"
#include "epan/conversation.h"

static int proto_x509 = -1;

static int hf_x509 = -1;
static int hf_TBSCertificate_version = -1;
static int hf_TBSCertificate_serialNumber = -1;

static gint ett_x509 = -1;
static gint ett_version = -1;
static gint ett_serial_num = -1;
static dissector_handle_t data_handle;

/*
From:
RFC 3280        Internet X.509 Public Key Infrastructure      April 2002

Certificate  ::=  SEQUENCE  {
        tbsCertificate       TBSCertificate,
        signatureAlgorithm   AlgorithmIdentifier,
        signatureValue       BIT STRING  }

   TBSCertificate  ::=  SEQUENCE  {
        version         [0]  EXPLICIT Version DEFAULT v1,
        serialNumber         CertificateSerialNumber,
        signature            AlgorithmIdentifier,
        issuer               Name,
        validity             Validity,
        subject              Name,
        subjectPublicKeyInfo SubjectPublicKeyInfo,
        issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
                             -- If present, version MUST be v2 or v3
        subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
                             -- If present, version MUST be v2 or v3
        extensions      [3]  EXPLICIT Extensions OPTIONAL
                             -- If present, version MUST be v3
        }

   Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }

   CertificateSerialNumber  ::=  INTEGER

   Validity ::= SEQUENCE {
        notBefore      Time,
        notAfter       Time }

   Time ::= CHOICE {
        utcTime        UTCTime,
        generalTime    GeneralizedTime }

   UniqueIdentifier  ::=  BIT STRING

   SubjectPublicKeyInfo  ::=  SEQUENCE  {
        algorithm            AlgorithmIdentifier,
        subjectPublicKey     BIT STRING  }

   Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension

   Extension  ::=  SEQUENCE  {
        extnID      OBJECT IDENTIFIER,
        critical    BOOLEAN DEFAULT FALSE,
        extnValue   OCTET STRING  }

*/

static int
dissect_TBSCertificate_version(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset)
{
	offset = dissect_ber_integer(pinfo, tree, tvb, offset, hf_TBSCertificate_version, &ett_version);
	return offset;
}

static ber_sequence TBSCertificate_sequence[1] = {
	{ BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_TBSCertificate_version }
};

static int
dissect_tbsCertificate(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset)
{
	offset = dissect_ber_sequence(TRUE, pinfo, tree, tvb, offset, TBSCertificate_sequence, -1, -1);
	return offset;
}

static int
dissect_TBSCertificate_serialNumber(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset)
{
	offset = dissect_ber_integer(pinfo, tree, tvb, offset, hf_TBSCertificate_serialNumber, &ett_serial_num);
	return offset;
}
/*
static int
dissect_TBSCertificate_signature(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset)
{
	proto_tree_add_text(tree, tvb, offset, 1, "dissect_TBSCertificate_signature");
	//offset = dissect_ber_sequence(FALSE, pinfo, tree, tvb, offset, TBSCertificate_signature, -1, -1);
	return offset;
}

static int
dissect_signatureAlgorithm(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset)
{
	proto_tree_add_text(tree, tvb, offset, 1, "dissect_signatureAlgorithm");
	return offset;
}

static int
dissect_signatureValue(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset)
{
	proto_tree_add_text(tree, tvb, offset, 1, "dissect_signatureValue");
	return offset;
}
*/
static ber_sequence Certificate_sequence[] = {
	{ BER_CLASS_UNI, BER_UNI_TAG_SEQUENCE, 0, dissect_tbsCertificate },
	{ BER_CLASS_UNI, BER_UNI_TAG_INTEGER, 0, dissect_TBSCertificate_serialNumber },
//	{ BER_CLASS_UNI, BER_UNI_TAG_SEQUENCE, 0, dissect_TBSCertificate_signature },
//	{ BER_CLASS_UNI, BER_UNI_TAG_SEQUENCE, 0, dissect_signatureAlgorithm },
//	{ BER_CLASS_UNI, BER_UNI_TAG_BITSTRING, 0, dissect_signatureValue },
	{ 0, 0, 0, NULL }
};

static void
dissect_x509(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	int offset = 0;

	offset = dissect_ber_sequence(TRUE, pinfo, tree, tvb, offset, Certificate_sequence, -1, -1);
}

void
proto_register_x509(void)
{
	static hf_register_info hf[] = {
		{ &hf_x509,
		  { "X509CERT", "x509cert", FT_NONE, BASE_NONE, NULL, 0x0,
		    "X509CERT", HFILL }},
		{ &hf_TBSCertificate_version,
		  {"version", "version", FT_UINT32, BASE_DEC, NULL, 0x0,
		    "version", HFILL }},
		{ &hf_TBSCertificate_serialNumber,
		  {"serial number", "serial_number", FT_UINT32, BASE_DEC, NULL, 0x0,
		    "serial number", HFILL }},

	};

	static gint *ett[] = {
		&ett_x509,
		&ett_version,
		&ett_serial_num,
	};

	proto_x509 = proto_register_protocol(
		"X509 Certificate",
		"X509-CERT", "x509-cert");

	proto_register_field_array(proto_x509, hf, array_length(hf));
	proto_register_subtree_array(ett, array_length(ett));

	register_dissector("X509", dissect_x509, proto_x509);
	
}