Blame src/data-identify.c

Packit Service 672cf4
/* data-identify.c - Try to identify the data
Packit Service 0ef63b
 * Copyright (C) 2013, 2016 g10 Code GmbH
Packit Service 0ef63b
 *
Packit Service 0ef63b
 * This file is part of GPGME.
Packit Service 0ef63b
 *
Packit Service 0ef63b
 * GPGME is free software; you can redistribute it and/or modify it
Packit Service 0ef63b
 * under the terms of the GNU Lesser General Public License as
Packit Service 0ef63b
 * published by the Free Software Foundation; either version 2.1 of
Packit Service 0ef63b
 * the License, or (at your option) any later version.
Packit Service 0ef63b
 *
Packit Service 0ef63b
 * GPGME is distributed in the hope that it will be useful, but
Packit Service 0ef63b
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 0ef63b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 0ef63b
 * Lesser General Public License for more details.
Packit Service 0ef63b
 *
Packit Service 0ef63b
 * You should have received a copy of the GNU Lesser General Public
Packit Service 0ef63b
 * License along with this program; if not, see <https://gnu.org/licenses/>.
Packit Service 0ef63b
 * SPDX-License-Identifier: LGPL-2.1-or-later
Packit Service 672cf4
 */
Packit Service 672cf4
Packit Service 672cf4
#if HAVE_CONFIG_H
Packit Service 672cf4
# include <config.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
#include <stdlib.h>
Packit Service 672cf4
#include <string.h>
Packit Service 672cf4
Packit Service 672cf4
#include "gpgme.h"
Packit Service 672cf4
#include "data.h"
Packit Service 672cf4
#include "util.h"
Packit Service 672cf4
#include "parsetlv.h"
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* The size of the sample data we take for detection.  */
Packit Service 672cf4
#define SAMPLE_SIZE 2048
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* OpenPGP packet types.  */
Packit Service 672cf4
enum
Packit Service 672cf4
  {
Packit Service 672cf4
    PKT_NONE	      = 0,
Packit Service 672cf4
    PKT_PUBKEY_ENC    = 1,  /* Public key encrypted packet. */
Packit Service 672cf4
    PKT_SIGNATURE     = 2,  /* Secret key encrypted packet. */
Packit Service 672cf4
    PKT_SYMKEY_ENC    = 3,  /* Session key packet. */
Packit Service 672cf4
    PKT_ONEPASS_SIG   = 4,  /* One pass sig packet. */
Packit Service 672cf4
    PKT_SECRET_KEY    = 5,  /* Secret key. */
Packit Service 672cf4
    PKT_PUBLIC_KEY    = 6,  /* Public key. */
Packit Service 672cf4
    PKT_SECRET_SUBKEY = 7,  /* Secret subkey. */
Packit Service 672cf4
    PKT_COMPRESSED    = 8,  /* Compressed data packet. */
Packit Service 672cf4
    PKT_ENCRYPTED     = 9,  /* Conventional encrypted data. */
Packit Service 672cf4
    PKT_MARKER	      = 10, /* Marker packet. */
Packit Service 672cf4
    PKT_PLAINTEXT     = 11, /* Literal data packet. */
Packit Service 672cf4
    PKT_RING_TRUST    = 12, /* Keyring trust packet. */
Packit Service 672cf4
    PKT_USER_ID	      = 13, /* User id packet. */
Packit Service 672cf4
    PKT_PUBLIC_SUBKEY = 14, /* Public subkey. */
Packit Service 672cf4
    PKT_OLD_COMMENT   = 16, /* Comment packet from an OpenPGP draft. */
Packit Service 672cf4
    PKT_ATTRIBUTE     = 17, /* PGP's attribute packet. */
Packit Service 672cf4
    PKT_ENCRYPTED_MDC = 18, /* Integrity protected encrypted data. */
Packit Service 672cf4
    PKT_MDC 	      = 19, /* Manipulation detection code packet. */
Packit Service 672cf4
  };
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static inline unsigned long
Packit Service 672cf4
buf32_to_ulong (const void *buffer)
Packit Service 672cf4
{
Packit Service 672cf4
  const unsigned char *p = buffer;
Packit Service 672cf4
Packit Service 672cf4
  return (((unsigned long)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Parse the next openpgp packet.  This function assumes a valid
Packit Service 672cf4
 * OpenPGP packet at the address pointed to by BUFPTR which has a
Packit Service 672cf4
 * maximum length as stored at BUFLEN.  Return the header information
Packit Service 672cf4
 * of that packet and advance the pointer stored at BUFPTR to the next
Packit Service 672cf4
 * packet; also adjust the length stored at BUFLEN to match the
Packit Service 672cf4
 * remaining bytes. If there are no more packets, store NULL at
Packit Service 672cf4
 * BUFPTR.  Return an non-zero error code on failure or the following
Packit Service 672cf4
 * data on success:
Packit Service 672cf4
 *
Packit Service 672cf4
 *  R_PKTTYPE = The packet type.
Packit Service 672cf4
 *  R_NTOTAL  = The total number of bytes of this packet
Packit Service 672cf4
 *
Packit Service 672cf4
 * If GPG_ERR_TRUNCATED is returned, a packet type is anyway stored at
Packit Service 672cf4
 * R_PKTTYPE but R_NOTAL won't have a usable value,
Packit Service 672cf4
 */
Packit Service 672cf4
static gpg_error_t
Packit Service 672cf4
next_openpgp_packet (unsigned char const **bufptr, size_t *buflen,
Packit Service 672cf4
                     int *r_pkttype, size_t *r_ntotal)
Packit Service 672cf4
{
Packit Service 672cf4
  const unsigned char *buf = *bufptr;
Packit Service 672cf4
  size_t len = *buflen;
Packit Service 672cf4
  int c, ctb, pkttype;
Packit Service 672cf4
  unsigned long pktlen;
Packit Service 672cf4
Packit Service 672cf4
  if (!len)
Packit Service 672cf4
    return gpg_error (GPG_ERR_NO_DATA);
Packit Service 672cf4
Packit Service 672cf4
  /* First some blacklisting.  */
Packit Service 672cf4
  if (len >= 4 && !memcmp (buf, "\x89PNG", 4))
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_PACKET); /* This is a PNG file.  */
Packit Service 672cf4
Packit Service 672cf4
  /* Start parsing.  */
Packit Service 672cf4
  ctb = *buf++; len--;
Packit Service 672cf4
  if ( !(ctb & 0x80) )
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_PACKET); /* Invalid CTB. */
Packit Service 672cf4
Packit Service 672cf4
  if ((ctb & 0x40))  /* New style (OpenPGP) CTB.  */
Packit Service 672cf4
    {
Packit Service 672cf4
      pkttype = (ctb & 0x3f);
Packit Service 672cf4
      if (!len)
Packit Service 672cf4
        return gpg_error (GPG_ERR_INV_PACKET); /* No 1st length byte. */
Packit Service 672cf4
      c = *buf++; len--;
Packit Service 672cf4
      if ( c < 192 )
Packit Service 672cf4
        pktlen = c;
Packit Service 672cf4
      else if ( c < 224 )
Packit Service 672cf4
        {
Packit Service 672cf4
          pktlen = (c - 192) * 256;
Packit Service 672cf4
          if (!len)
Packit Service 672cf4
            return gpg_error (GPG_ERR_INV_PACKET); /* No 2nd length byte. */
Packit Service 672cf4
          c = *buf++; len--;
Packit Service 672cf4
          pktlen += c + 192;
Packit Service 672cf4
        }
Packit Service 672cf4
      else if (c == 255)
Packit Service 672cf4
        {
Packit Service 672cf4
          if (len < 4)
Packit Service 672cf4
            return gpg_error (GPG_ERR_INV_PACKET); /* No length bytes. */
Packit Service 672cf4
          pktlen = buf32_to_ulong (buf);
Packit Service 672cf4
          buf += 4;
Packit Service 672cf4
          len -= 4;
Packit Service 672cf4
        }
Packit Service 672cf4
      else /* Partial length encoding. */
Packit Service 672cf4
        {
Packit Service 672cf4
          pktlen = 0;
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
  else /* Old style CTB.  */
Packit Service 672cf4
    {
Packit Service 672cf4
      int lenbytes;
Packit Service 672cf4
Packit Service 672cf4
      pktlen = 0;
Packit Service 672cf4
      pkttype = (ctb>>2)&0xf;
Packit Service 672cf4
      lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
Packit Service 672cf4
      if (len < lenbytes)
Packit Service 672cf4
        return gpg_error (GPG_ERR_INV_PACKET); /* Not enough length bytes.  */
Packit Service 672cf4
      for (; lenbytes; lenbytes--)
Packit Service 672cf4
        {
Packit Service 672cf4
          pktlen <<= 8;
Packit Service 672cf4
          pktlen |= *buf++; len--;
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  /* Do some basic sanity check.  */
Packit Service 672cf4
  switch (pkttype)
Packit Service 672cf4
    {
Packit Service 672cf4
    case PKT_PUBKEY_ENC:
Packit Service 672cf4
    case PKT_SIGNATURE:
Packit Service 672cf4
    case PKT_SYMKEY_ENC:
Packit Service 672cf4
    case PKT_ONEPASS_SIG:
Packit Service 672cf4
    case PKT_SECRET_KEY:
Packit Service 672cf4
    case PKT_PUBLIC_KEY:
Packit Service 672cf4
    case PKT_SECRET_SUBKEY:
Packit Service 672cf4
    case PKT_COMPRESSED:
Packit Service 672cf4
    case PKT_ENCRYPTED:
Packit Service 672cf4
    case PKT_MARKER:
Packit Service 672cf4
    case PKT_PLAINTEXT:
Packit Service 672cf4
    case PKT_RING_TRUST:
Packit Service 672cf4
    case PKT_USER_ID:
Packit Service 672cf4
    case PKT_PUBLIC_SUBKEY:
Packit Service 672cf4
    case PKT_OLD_COMMENT:
Packit Service 672cf4
    case PKT_ATTRIBUTE:
Packit Service 672cf4
    case PKT_ENCRYPTED_MDC:
Packit Service 672cf4
    case PKT_MDC:
Packit Service 672cf4
      break; /* Okay these are allowed packets. */
Packit Service 672cf4
    default:
Packit Service 672cf4
      return gpg_error (GPG_ERR_UNEXPECTED);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (pktlen > len)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* Packet length header too long.  This is possible because we
Packit Service 672cf4
       * may have only a truncated image.  */
Packit Service 672cf4
      *r_pkttype = pkttype;
Packit Service 672cf4
      *r_ntotal = 0;
Packit Service 672cf4
      *bufptr = NULL;
Packit Service 672cf4
      return gpg_error (GPG_ERR_TRUNCATED);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  *r_pkttype = pkttype;
Packit Service 672cf4
  *r_ntotal = (buf - *bufptr) + pktlen;
Packit Service 672cf4
Packit Service 672cf4
  *bufptr = buf + pktlen;
Packit Service 672cf4
  *buflen = len - pktlen;
Packit Service 672cf4
  if (!*buflen)
Packit Service 672cf4
    *bufptr = NULL;
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Detection of PGP binary data.  This function parses an OpenPGP
Packit Service 672cf4
 * message.  This parser is robust enough to work on a truncated
Packit Service 672cf4
 * version.  Returns a GPGME_DATA_TYPE_.  */
Packit Service 672cf4
static gpgme_data_type_t
Packit Service 672cf4
pgp_binary_detection (const void *image_arg, size_t imagelen)
Packit Service 672cf4
{
Packit Service 672cf4
  gpg_error_t err = 0;
Packit Service 672cf4
  const unsigned char *image = image_arg;
Packit Service 672cf4
  size_t n;
Packit Service 672cf4
  int pkttype;
Packit Service 672cf4
  int anypacket = 0;
Packit Service 672cf4
  int allsignatures = 0;
Packit Service 672cf4
Packit Service 672cf4
  while (!err && image)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = next_openpgp_packet (&image, &imagelen, &pkttype, &n);
Packit Service 672cf4
      if (gpg_err_code (err) == GPG_ERR_TRUNCATED)
Packit Service 672cf4
        ;
Packit Service 672cf4
      else if (err)
Packit Service 672cf4
        break;
Packit Service 672cf4
Packit Service 672cf4
      /* Skip all leading marker packets.  */
Packit Service 672cf4
      if (!anypacket && pkttype == PKT_MARKER)
Packit Service 672cf4
        continue;
Packit Service 672cf4
Packit Service 672cf4
      if (pkttype == PKT_SIGNATURE)
Packit Service 672cf4
        {
Packit Service 672cf4
          if (!anypacket)
Packit Service 672cf4
            allsignatures = 1;
Packit Service 672cf4
        }
Packit Service 672cf4
      else
Packit Service 672cf4
        allsignatures = 0;
Packit Service 672cf4
Packit Service 672cf4
      switch (pkttype)
Packit Service 672cf4
        {
Packit Service 672cf4
        case PKT_SIGNATURE:
Packit Service 672cf4
          break;  /* We decide later.  */
Packit Service 672cf4
Packit Service 672cf4
        case PKT_PLAINTEXT:
Packit Service 672cf4
          /* Old style signature format: {sig}+,plaintext */
Packit Service 672cf4
          if (allsignatures)
Packit Service 672cf4
            return GPGME_DATA_TYPE_PGP_SIGNED;
Packit Service 672cf4
          break;
Packit Service 672cf4
Packit Service 672cf4
        case PKT_ONEPASS_SIG:
Packit Service 672cf4
          return GPGME_DATA_TYPE_PGP_SIGNED;
Packit Service 672cf4
Packit Service 672cf4
        case PKT_SECRET_KEY:
Packit Service 672cf4
        case PKT_PUBLIC_KEY:
Packit Service 672cf4
          return GPGME_DATA_TYPE_PGP_KEY;
Packit Service 672cf4
Packit Service 672cf4
        case PKT_SECRET_SUBKEY:
Packit Service 672cf4
        case PKT_PUBLIC_SUBKEY:
Packit Service 672cf4
          return GPGME_DATA_TYPE_PGP_OTHER;
Packit Service 672cf4
        case PKT_PUBKEY_ENC:
Packit Service 672cf4
        case PKT_SYMKEY_ENC:
Packit Service 672cf4
          return GPGME_DATA_TYPE_PGP_ENCRYPTED;
Packit Service 672cf4
Packit Service 672cf4
        case PKT_COMPRESSED:
Packit Service 672cf4
          /* If this is the first packet we assume that that a signed
Packit Service 672cf4
           * packet follows.  We do not want to uncompress it here due
Packit Service 0ef63b
           * to the need of a lot of code and the potential DoS. */
Packit Service 672cf4
          if (!anypacket)
Packit Service 672cf4
            return GPGME_DATA_TYPE_PGP_SIGNED;
Packit Service 672cf4
          return GPGME_DATA_TYPE_PGP_OTHER;
Packit Service 672cf4
Packit Service 672cf4
        default:
Packit Service 672cf4
          return GPGME_DATA_TYPE_PGP_OTHER;
Packit Service 672cf4
        }
Packit Service 672cf4
      anypacket = 1;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (allsignatures)
Packit Service 672cf4
    return  GPGME_DATA_TYPE_PGP_SIGNATURE;
Packit Service 672cf4
Packit Service 672cf4
  return GPGME_DATA_TYPE_UNKNOWN;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* This is probably an armored "PGP MESSAGE" which can encode
Packit Service 672cf4
 * different PGP data types.  STRING is modified after a call to this
Packit Service 672cf4
 * function. */
Packit Service 672cf4
static gpgme_data_type_t
Packit Service 672cf4
inspect_pgp_message (char *string)
Packit Service 672cf4
{
Packit Service 672cf4
  struct b64state state;
Packit Service 672cf4
  size_t nbytes;
Packit Service 672cf4
Packit Service 672cf4
  if (_gpgme_b64dec_start (&state, ""))
Packit Service 672cf4
    return GPGME_DATA_TYPE_INVALID; /* oops */
Packit Service 672cf4
Packit Service 672cf4
  if (_gpgme_b64dec_proc (&state, string, strlen (string), &nbytes))
Packit Service 672cf4
    {
Packit Service 672cf4
      _gpgme_b64dec_finish (&state);
Packit Service 672cf4
      return GPGME_DATA_TYPE_UNKNOWN; /* bad encoding etc. */
Packit Service 672cf4
    }
Packit Service 672cf4
  _gpgme_b64dec_finish (&state);
Packit Service 672cf4
  string[nbytes] = 0; /* Better append a Nul. */
Packit Service 672cf4
Packit Service 672cf4
  return pgp_binary_detection (string, nbytes);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Note that DATA may be binary but a final nul is required so that
Packit Service 672cf4
   string operations will find a terminator.
Packit Service 672cf4
Packit Service 672cf4
   Returns: GPGME_DATA_TYPE_xxxx */
Packit Service 672cf4
static gpgme_data_type_t
Packit Service 672cf4
basic_detection (char *data, size_t datalen)
Packit Service 672cf4
{
Packit Service 672cf4
  tlvinfo_t ti;
Packit Service 672cf4
  const char *s;
Packit Service 672cf4
  size_t n;
Packit Service 672cf4
  int maybe_p12 = 0;
Packit Service 672cf4
Packit Service 672cf4
  if (datalen < 24) /* Object is probably too short for detection.  */
Packit Service 672cf4
    return GPGME_DATA_TYPE_UNKNOWN;
Packit Service 672cf4
Packit Service 672cf4
  /* This is a common example of a CMS object - it is obvious that we
Packit Service 672cf4
     only need to read a few bytes to get to the OID:
Packit Service 672cf4
  30 82 0B 59 06 09 2A 86 48 86 F7 0D 01 07 02 A0 82 0B 4A 30 82 0B 46 02
Packit Service 672cf4
  ----------- ++++++++++++++++++++++++++++++++
Packit Service 672cf4
  SEQUENCE    OID (signedData)
Packit Service 672cf4
  (2 byte len)
Packit Service 672cf4
Packit Service 672cf4
    A PKCS#12 message is:
Packit Service 672cf4
Packit Service 672cf4
  30 82 08 59 02 01 03 30 82 08 1F 06 09 2A 86 48 86 F7 0D 01 07 01 A0 82
Packit Service 672cf4
  ----------- ++++++++ ----------- ++++++++++++++++++++++++++++++++
Packit Service 672cf4
  SEQUENCE    INTEGER  SEQUENCE    OID (data)
Packit Service 672cf4
Packit Service 672cf4
    A X.509 certificate is:
Packit Service 672cf4
Packit Service 672cf4
  30 82 05 B8 30 82 04 A0 A0 03 02 01 02 02 07 15 46 A0 BF 30 07 39 30 0D
Packit Service 672cf4
  ----------- +++++++++++ ----- ++++++++ --------------------------
Packit Service 672cf4
  SEQUENCE    SEQUENCE    [0]   INTEGER  INTEGER                    SEQU
Packit Service 672cf4
              (tbs)            (version) (s/n)                      (Algo)
Packit Service 672cf4
Packit Service 672cf4
    Thus we need to read at least 22 bytes, we add 2 bytes to cope with
Packit Service 672cf4
    length headers stored with 4 bytes.
Packit Service 672cf4
  */
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
  s = data;
Packit Service 672cf4
  n = datalen;
Packit Service 672cf4
Packit Service 672cf4
  if (parse_tlv (&s, &n, &ti))
Packit Service 672cf4
    goto try_pgp; /* Not properly BER encoded.  */
Packit Service 672cf4
  if (!(ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_SEQUENCE
Packit Service 672cf4
        && ti.is_cons))
Packit Service 672cf4
    goto try_pgp; /* A CMS object always starts with a sequence.  */
Packit Service 672cf4
Packit Service 672cf4
  if (parse_tlv (&s, &n, &ti))
Packit Service 672cf4
    goto try_pgp; /* Not properly BER encoded.  */
Packit Service 672cf4
  if (ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_SEQUENCE
Packit Service 672cf4
      && ti.is_cons && n >= ti.length)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (parse_tlv (&s, &n, &ti))
Packit Service 672cf4
        goto try_pgp;
Packit Service 672cf4
      if (!(ti.cls == ASN1_CLASS_CONTEXT && ti.tag == 0
Packit Service 672cf4
            && ti.is_cons && ti.length == 3 && n >= ti.length))
Packit Service 672cf4
        goto try_pgp;
Packit Service 672cf4
Packit Service 672cf4
      if (parse_tlv (&s, &n, &ti))
Packit Service 672cf4
        goto try_pgp;
Packit Service 672cf4
      if (!(ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_INTEGER
Packit Service 672cf4
            && !ti.is_cons && ti.length == 1 && n && (*s == 1 || *s == 2)))
Packit Service 672cf4
        goto try_pgp;
Packit Service 672cf4
      s++;
Packit Service 672cf4
      n--;
Packit Service 672cf4
      if (!(ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_INTEGER
Packit Service 672cf4
            && !ti.is_cons))
Packit Service 672cf4
        goto try_pgp;
Packit Service 672cf4
      /* Because the now following S/N may be larger than the sample
Packit Service 672cf4
         data we have, we stop parsing here and don't check for the
Packit Service 672cf4
         algorithm ID.  */
Packit Service 672cf4
      return GPGME_DATA_TYPE_X509_CERT;
Packit Service 672cf4
    }
Packit Service 672cf4
  if (ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_INTEGER
Packit Service 672cf4
      && !ti.is_cons && ti.length == 1 && n && *s == 3)
Packit Service 672cf4
    {
Packit Service 672cf4
      maybe_p12 = 1;
Packit Service 672cf4
      s++;
Packit Service 672cf4
      n--;
Packit Service 672cf4
      if (parse_tlv (&s, &n, &ti))
Packit Service 672cf4
        goto try_pgp;
Packit Service 672cf4
      if (!(ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_SEQUENCE
Packit Service 672cf4
            && ti.is_cons))
Packit Service 672cf4
        goto try_pgp;
Packit Service 672cf4
      if (parse_tlv (&s, &n, &ti))
Packit Service 672cf4
        goto try_pgp;
Packit Service 672cf4
    }
Packit Service 672cf4
  if (ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_OBJECT_ID
Packit Service 672cf4
      && !ti.is_cons && ti.length && n >= ti.length)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (ti.length == 9)
Packit Service 672cf4
        {
Packit Service 672cf4
          if (!memcmp (s, "\x2A\x86\x48\x86\xF7\x0D\x01\x07\x01", 9))
Packit Service 672cf4
            {
Packit Service 672cf4
              /* Data.  */
Packit Service 672cf4
              return (maybe_p12 ? GPGME_DATA_TYPE_PKCS12
Packit Service 672cf4
                      /*     */ : GPGME_DATA_TYPE_CMS_OTHER);
Packit Service 672cf4
            }
Packit Service 672cf4
          if (!memcmp (s, "\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02", 9))
Packit Service 672cf4
            {
Packit Service 672cf4
              /* Signed Data.  */
Packit Service 672cf4
              return (maybe_p12 ? GPGME_DATA_TYPE_PKCS12
Packit Service 672cf4
                      /*     */ : GPGME_DATA_TYPE_CMS_SIGNED);
Packit Service 672cf4
            }
Packit Service 672cf4
          if (!memcmp (s, "\x2A\x86\x48\x86\xF7\x0D\x01\x07\x03", 9))
Packit Service 672cf4
            return GPGME_DATA_TYPE_CMS_ENCRYPTED; /* Enveloped Data.  */
Packit Service 672cf4
          if (!memcmp (s, "\x2A\x86\x48\x86\xF7\x0D\x01\x07\x05", 9))
Packit Service 672cf4
            return GPGME_DATA_TYPE_CMS_OTHER; /* Digested Data.  */
Packit Service 672cf4
          if (!memcmp (s, "\x2A\x86\x48\x86\xF7\x0D\x01\x07\x06", 9))
Packit Service 672cf4
            return GPGME_DATA_TYPE_CMS_OTHER; /* Encrypted Data.  */
Packit Service 672cf4
        }
Packit Service 672cf4
      else if (ti.length == 11)
Packit Service 672cf4
        {
Packit Service 672cf4
          if (!memcmp (s, "\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x01\x02", 11))
Packit Service 672cf4
            return GPGME_DATA_TYPE_CMS_OTHER; /* Auth Data.  */
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
 try_pgp:
Packit Service 672cf4
  /* Check whether this might be a non-armored PGP message.  We need
Packit Service 672cf4
     to do this before checking for armor lines, so that we don't get
Packit Service 672cf4
     fooled by armored messages inside a signed binary PGP message.  */
Packit Service 672cf4
  if ((data[0] & 0x80))
Packit Service 672cf4
    {
Packit Service 672cf4
      /* That might be a binary PGP message.  At least it is not plain
Packit Service 672cf4
         ASCII.  Of course this might be certain lead-in text of
Packit Service 672cf4
         armored CMS messages.  However, I am not sure whether this is
Packit Service 672cf4
         at all defined and in any case it is uncommon.  Thus we don't
Packit Service 672cf4
         do any further plausibility checks but stupidly assume no CMS
Packit Service 672cf4
         armored data will follow.  */
Packit Service 672cf4
      return pgp_binary_detection (data, datalen);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  /* Now check whether there are armor lines.  */
Packit Service 672cf4
  for (s = data; s && *s; s = (*s=='\n')?(s+1):((s=strchr (s,'\n'))?(s+1):s))
Packit Service 672cf4
    {
Packit Service 672cf4
      if (!strncmp (s, "-----BEGIN ", 11))
Packit Service 672cf4
        {
Packit Service 672cf4
          if (!strncmp (s+11, "SIGNED ", 7))
Packit Service 672cf4
            return GPGME_DATA_TYPE_CMS_SIGNED;
Packit Service 672cf4
          if (!strncmp (s+11, "ENCRYPTED ", 10))
Packit Service 672cf4
            return GPGME_DATA_TYPE_CMS_ENCRYPTED;
Packit Service 672cf4
          if (!strncmp (s+11, "PGP ", 4))
Packit Service 672cf4
            {
Packit Service 672cf4
              if (!strncmp (s+15, "SIGNATURE", 9))
Packit Service 672cf4
                return GPGME_DATA_TYPE_PGP_SIGNATURE;
Packit Service 672cf4
              if (!strncmp (s+15, "SIGNED MESSAGE", 14))
Packit Service 672cf4
                return GPGME_DATA_TYPE_PGP_SIGNED;
Packit Service 672cf4
              if (!strncmp (s+15, "PUBLIC KEY BLOCK", 16))
Packit Service 672cf4
                return GPGME_DATA_TYPE_PGP_KEY;
Packit Service 672cf4
              if (!strncmp (s+15, "PRIVATE KEY BLOCK", 17))
Packit Service 672cf4
                return GPGME_DATA_TYPE_PGP_KEY;
Packit Service 672cf4
              if (!strncmp (s+15, "SECRET KEY BLOCK", 16))
Packit Service 672cf4
                return GPGME_DATA_TYPE_PGP_KEY;
Packit Service 672cf4
              if (!strncmp (s+15, "ARMORED FILE", 12))
Packit Service 672cf4
                return GPGME_DATA_TYPE_UNKNOWN;
Packit Service 672cf4
Packit Service 672cf4
              return inspect_pgp_message (data);
Packit Service 672cf4
            }
Packit Service 672cf4
          if (!strncmp (s+11, "CERTIFICATE", 11))
Packit Service 672cf4
            return GPGME_DATA_TYPE_X509_CERT;
Packit Service 672cf4
          if (!strncmp (s+11, "PKCS12", 6))
Packit Service 672cf4
            return GPGME_DATA_TYPE_PKCS12;
Packit Service 672cf4
          return GPGME_DATA_TYPE_CMS_OTHER; /* Not PGP, thus we assume CMS.  */
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  return GPGME_DATA_TYPE_UNKNOWN;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Try to detect the type of the data.  Note that this function works
Packit Service 672cf4
   only on seekable data objects.  The function tries to reset the
Packit Service 672cf4
   file pointer but there is no guarantee that it will work.
Packit Service 672cf4
Packit Service 672cf4
   FIXME: We may want to add internal buffering so that this function
Packit Service 0ef63b
   can be implemented for almost all kind of data objects.
Packit Service 672cf4
 */
Packit Service 672cf4
gpgme_data_type_t
Packit Service 672cf4
gpgme_data_identify (gpgme_data_t dh, int reserved)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_data_type_t result;
Packit Service 672cf4
  char *sample;
Packit Service 672cf4
  int n;
Packit Service 672cf4
  gpgme_off_t off;
Packit Service 672cf4
Packit Service 672cf4
  (void)reserved;
Packit Service 672cf4
Packit Service 672cf4
  /* Check whether we can seek the data object.  */
Packit Service 672cf4
  off = gpgme_data_seek (dh, 0, SEEK_CUR);
Packit Service 672cf4
  if (off == (gpgme_off_t)(-1))
Packit Service 672cf4
    return GPGME_DATA_TYPE_INVALID;
Packit Service 672cf4
Packit Service 672cf4
  /* Allocate a buffer and read the data. */
Packit Service 672cf4
  sample = malloc (SAMPLE_SIZE);
Packit Service 672cf4
  if (!sample)
Packit Service 672cf4
    return GPGME_DATA_TYPE_INVALID; /* Ooops.  */
Packit Service 672cf4
  n = gpgme_data_read (dh, sample, SAMPLE_SIZE - 1);
Packit Service 672cf4
  if (n < 0)
Packit Service 672cf4
    {
Packit Service 672cf4
      free (sample);
Packit Service 672cf4
      return GPGME_DATA_TYPE_INVALID; /* Ooops.  */
Packit Service 672cf4
    }
Packit Service 672cf4
  sample[n] = 0;  /* (Required for our string functions.)  */
Packit Service 672cf4
Packit Service 672cf4
  result = basic_detection (sample, n);
Packit Service 672cf4
  free (sample);
Packit Service 672cf4
  gpgme_data_seek (dh, off, SEEK_SET);
Packit Service 672cf4
Packit Service 672cf4
  return result;
Packit Service 672cf4
}