LCOV - code coverage report
Current view: top level - cipher - pubkey-util.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 534 0.0 %
Date: 2016-12-15 12:59:22 Functions: 0 10 0.0 %

          Line data    Source code
       1             : /* pubkey-util.c - Supporting functions for all pubkey modules.
       2             :  * Copyright (C) 1998, 1999, 2000, 2002, 2003, 2005,
       3             :  *               2007, 2008, 2011 Free Software Foundation, Inc.
       4             :  * Copyright (C) 2013, 2015 g10 Code GmbH
       5             :  *
       6             :  * This file is part of Libgcrypt.
       7             :  *
       8             :  * Libgcrypt is free software; you can redistribute it and/or modify
       9             :  * it under the terms of the GNU Lesser General Public License as
      10             :  * published by the Free Software Foundation; either version 2.1 of
      11             :  * the License, or (at your option) any later version.
      12             :  *
      13             :  * Libgcrypt is distributed in the hope that it will be useful,
      14             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :  * GNU Lesser General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU Lesser General Public
      19             :  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
      20             :  */
      21             : 
      22             : #include <config.h>
      23             : #include <stdio.h>
      24             : #include <stdlib.h>
      25             : #include <string.h>
      26             : 
      27             : #include "g10lib.h"
      28             : #include "mpi.h"
      29             : #include "cipher.h"
      30             : #include "pubkey-internal.h"
      31             : 
      32             : 
      33             : /* Callback for the pubkey algorithm code to verify PSS signatures.
      34             :    OPAQUE is the data provided by the actual caller.  The meaning of
      35             :    TMP depends on the actual algorithm (but there is only RSA); now
      36             :    for RSA it is the output of running the public key function on the
      37             :    input.  */
      38             : static int
      39           0 : pss_verify_cmp (void *opaque, gcry_mpi_t tmp)
      40             : {
      41           0 :   struct pk_encoding_ctx *ctx = opaque;
      42           0 :   gcry_mpi_t hash = ctx->verify_arg;
      43             : 
      44           0 :   return _gcry_rsa_pss_verify (hash, tmp, ctx->nbits - 1,
      45             :                                ctx->hash_algo, ctx->saltlen);
      46             : }
      47             : 
      48             : 
      49             : /* Parser for a flag list.  On return the encoding is stored at
      50             :    R_ENCODING and the flags are stored at R_FLAGS.  If any of them is
      51             :    not needed, NULL may be passed.  The function returns 0 on success
      52             :    or an error code. */
      53             : gpg_err_code_t
      54           0 : _gcry_pk_util_parse_flaglist (gcry_sexp_t list,
      55             :                               int *r_flags, enum pk_encoding *r_encoding)
      56             : {
      57           0 :   gpg_err_code_t rc = 0;
      58             :   const char *s;
      59             :   size_t n;
      60             :   int i;
      61           0 :   int encoding = PUBKEY_ENC_UNKNOWN;
      62           0 :   int flags = 0;
      63           0 :   int igninvflag = 0;
      64             : 
      65           0 :   for (i = list ? sexp_length (list)-1 : 0; i > 0; i--)
      66             :     {
      67           0 :       s = sexp_nth_data (list, i, &n);
      68           0 :       if (!s)
      69           0 :         continue; /* Not a data element. */
      70             : 
      71           0 :       switch (n)
      72             :         {
      73             :         case 3:
      74           0 :           if (!memcmp (s, "pss", 3) && encoding == PUBKEY_ENC_UNKNOWN)
      75             :             {
      76           0 :               encoding = PUBKEY_ENC_PSS;
      77           0 :               flags |= PUBKEY_FLAG_FIXEDLEN;
      78             :             }
      79           0 :           else if (!memcmp (s, "raw", 3) && encoding == PUBKEY_ENC_UNKNOWN)
      80             :             {
      81           0 :               encoding = PUBKEY_ENC_RAW;
      82           0 :               flags |= PUBKEY_FLAG_RAW_FLAG; /* Explicitly given.  */
      83             :             }
      84           0 :           else if (!igninvflag)
      85           0 :             rc = GPG_ERR_INV_FLAG;
      86           0 :           break;
      87             : 
      88             :         case 4:
      89           0 :           if (!memcmp (s, "comp", 4))
      90           0 :             flags |= PUBKEY_FLAG_COMP;
      91           0 :           else if (!memcmp (s, "oaep", 4) && encoding == PUBKEY_ENC_UNKNOWN)
      92             :             {
      93           0 :               encoding = PUBKEY_ENC_OAEP;
      94           0 :               flags |= PUBKEY_FLAG_FIXEDLEN;
      95             :             }
      96           0 :           else if (!memcmp (s, "gost", 4))
      97             :             {
      98           0 :               encoding = PUBKEY_ENC_RAW;
      99           0 :               flags |= PUBKEY_FLAG_GOST;
     100             :             }
     101           0 :           else if (!igninvflag)
     102           0 :             rc = GPG_ERR_INV_FLAG;
     103           0 :           break;
     104             : 
     105             :         case 5:
     106           0 :           if (!memcmp (s, "eddsa", 5))
     107             :             {
     108           0 :               encoding = PUBKEY_ENC_RAW;
     109           0 :               flags |= PUBKEY_FLAG_EDDSA;
     110           0 :               flags |= PUBKEY_FLAG_DJB_TWEAK;
     111             :             }
     112           0 :           else if (!memcmp (s, "pkcs1", 5) && encoding == PUBKEY_ENC_UNKNOWN)
     113             :             {
     114           0 :               encoding = PUBKEY_ENC_PKCS1;
     115           0 :               flags |= PUBKEY_FLAG_FIXEDLEN;
     116             :             }
     117           0 :           else if (!memcmp (s, "param", 5))
     118           0 :             flags |= PUBKEY_FLAG_PARAM;
     119           0 :           else if (!igninvflag)
     120           0 :             rc = GPG_ERR_INV_FLAG;
     121           0 :           break;
     122             : 
     123             :         case 6:
     124           0 :           if (!memcmp (s, "nocomp", 6))
     125           0 :             flags |= PUBKEY_FLAG_NOCOMP;
     126           0 :           else if (!igninvflag)
     127           0 :             rc = GPG_ERR_INV_FLAG;
     128           0 :           break;
     129             : 
     130             :         case 7:
     131           0 :           if (!memcmp (s, "rfc6979", 7))
     132           0 :             flags |= PUBKEY_FLAG_RFC6979;
     133           0 :           else if (!memcmp (s, "noparam", 7))
     134             :             ; /* Ignore - it is the default.  */
     135           0 :           else if (!igninvflag)
     136           0 :             rc = GPG_ERR_INV_FLAG;
     137           0 :           break;
     138             : 
     139             :         case 8:
     140           0 :           if (!memcmp (s, "use-x931", 8))
     141           0 :             flags |= PUBKEY_FLAG_USE_X931;
     142           0 :           else if (!igninvflag)
     143           0 :             rc = GPG_ERR_INV_FLAG;
     144           0 :           break;
     145             : 
     146             :         case 9:
     147           0 :           if (!memcmp (s, "pkcs1-raw", 9) && encoding == PUBKEY_ENC_UNKNOWN)
     148             :             {
     149           0 :               encoding = PUBKEY_ENC_PKCS1_RAW;
     150           0 :               flags |= PUBKEY_FLAG_FIXEDLEN;
     151             :             }
     152           0 :           else if (!memcmp (s, "djb-tweak", 9))
     153             :             {
     154           0 :               encoding = PUBKEY_ENC_RAW;
     155           0 :               flags |= PUBKEY_FLAG_DJB_TWEAK;
     156             :             }
     157           0 :           else if (!igninvflag)
     158           0 :             rc = GPG_ERR_INV_FLAG;
     159           0 :           break;
     160             : 
     161             :         case 10:
     162           0 :           if (!memcmp (s, "igninvflag", 10))
     163           0 :             igninvflag = 1;
     164           0 :           else if (!memcmp (s, "no-keytest", 10))
     165           0 :             flags |= PUBKEY_FLAG_NO_KEYTEST;
     166           0 :           else if (!igninvflag)
     167           0 :             rc = GPG_ERR_INV_FLAG;
     168           0 :           break;
     169             : 
     170             :         case 11:
     171           0 :           if (!memcmp (s, "no-blinding", 11))
     172           0 :             flags |= PUBKEY_FLAG_NO_BLINDING;
     173           0 :           else if (!memcmp (s, "use-fips186", 11))
     174           0 :             flags |= PUBKEY_FLAG_USE_FIPS186;
     175           0 :           else if (!igninvflag)
     176           0 :             rc = GPG_ERR_INV_FLAG;
     177           0 :           break;
     178             : 
     179             :         case 13:
     180           0 :           if (!memcmp (s, "use-fips186-2", 13))
     181           0 :             flags |= PUBKEY_FLAG_USE_FIPS186_2;
     182           0 :           else if (!memcmp (s, "transient-key", 13))
     183           0 :             flags |= PUBKEY_FLAG_TRANSIENT_KEY;
     184           0 :           else if (!igninvflag)
     185           0 :             rc = GPG_ERR_INV_FLAG;
     186           0 :           break;
     187             : 
     188             :         default:
     189           0 :           if (!igninvflag)
     190           0 :             rc = GPG_ERR_INV_FLAG;
     191           0 :           break;
     192             :         }
     193             :     }
     194             : 
     195           0 :   if (r_flags)
     196           0 :     *r_flags = flags;
     197           0 :   if (r_encoding)
     198           0 :     *r_encoding = encoding;
     199             : 
     200           0 :   return rc;
     201             : }
     202             : 
     203             : 
     204             : static int
     205           0 : get_hash_algo (const char *s, size_t n)
     206             : {
     207             :   static const struct { const char *name; int algo; } hashnames[] = {
     208             :     { "sha1",   GCRY_MD_SHA1 },
     209             :     { "md5",    GCRY_MD_MD5 },
     210             :     { "sha256", GCRY_MD_SHA256 },
     211             :     { "ripemd160", GCRY_MD_RMD160 },
     212             :     { "rmd160", GCRY_MD_RMD160 },
     213             :     { "sha384", GCRY_MD_SHA384 },
     214             :     { "sha512", GCRY_MD_SHA512 },
     215             :     { "sha224", GCRY_MD_SHA224 },
     216             :     { "md2",    GCRY_MD_MD2 },
     217             :     { "md4",    GCRY_MD_MD4 },
     218             :     { "tiger",  GCRY_MD_TIGER },
     219             :     { "haval",  GCRY_MD_HAVAL },
     220             :     { "sha3-224", GCRY_MD_SHA3_224 },
     221             :     { "sha3-256", GCRY_MD_SHA3_256 },
     222             :     { "sha3-384", GCRY_MD_SHA3_384 },
     223             :     { "sha3-512", GCRY_MD_SHA3_512 },
     224             :     { NULL, 0 }
     225             :   };
     226             :   int algo;
     227             :   int i;
     228             : 
     229           0 :   for (i=0; hashnames[i].name; i++)
     230             :     {
     231           0 :       if ( strlen (hashnames[i].name) == n
     232           0 :            && !memcmp (hashnames[i].name, s, n))
     233           0 :         break;
     234             :     }
     235           0 :   if (hashnames[i].name)
     236           0 :     algo = hashnames[i].algo;
     237             :   else
     238             :     {
     239             :       /* In case of not listed or dynamically allocated hash
     240             :          algorithm we fall back to this somewhat slower
     241             :          method.  Further, it also allows to use OIDs as
     242             :          algorithm names. */
     243             :       char *tmpname;
     244             : 
     245           0 :       tmpname = xtrymalloc (n+1);
     246           0 :       if (!tmpname)
     247           0 :         algo = 0;  /* Out of core - silently give up.  */
     248             :       else
     249             :         {
     250           0 :           memcpy (tmpname, s, n);
     251           0 :           tmpname[n] = 0;
     252           0 :           algo = _gcry_md_map_name (tmpname);
     253           0 :           xfree (tmpname);
     254             :         }
     255             :     }
     256           0 :   return algo;
     257             : }
     258             : 
     259             : 
     260             : /* Get the "nbits" parameter from an s-expression of the format:
     261             :  *
     262             :  *   (algo
     263             :  *     (parameter_name_1 ....)
     264             :  *      ....
     265             :  *     (parameter_name_n ....))
     266             :  *
     267             :  * Example:
     268             :  *
     269             :  *   (rsa
     270             :  *     (nbits 4:2048))
     271             :  *
     272             :  * On success the value for nbits is stored at R_NBITS.  If no nbits
     273             :  * parameter is found, the function returns success and stores 0 at
     274             :  * R_NBITS.  For parsing errors the function returns an error code and
     275             :  * stores 0 at R_NBITS.
     276             :  */
     277             : gpg_err_code_t
     278           0 : _gcry_pk_util_get_nbits (gcry_sexp_t list, unsigned int *r_nbits)
     279             : {
     280             :   char buf[50];
     281             :   const char *s;
     282             :   size_t n;
     283             : 
     284           0 :   *r_nbits = 0;
     285             : 
     286           0 :   list = sexp_find_token (list, "nbits", 0);
     287           0 :   if (!list)
     288           0 :     return 0; /* No NBITS found.  */
     289             : 
     290           0 :   s = sexp_nth_data (list, 1, &n);
     291           0 :   if (!s || n >= DIM (buf) - 1 )
     292             :     {
     293             :       /* NBITS given without a cdr.  */
     294           0 :       sexp_release (list);
     295           0 :       return GPG_ERR_INV_OBJ;
     296             :     }
     297           0 :   memcpy (buf, s, n);
     298           0 :   buf[n] = 0;
     299           0 :   *r_nbits = (unsigned int)strtoul (buf, NULL, 0);
     300           0 :   sexp_release (list);
     301           0 :   return 0;
     302             : }
     303             : 
     304             : 
     305             : /* Get the optional "rsa-use-e" parameter from an s-expression of the
     306             :  * format:
     307             :  *
     308             :  *   (algo
     309             :  *     (parameter_name_1 ....)
     310             :  *      ....
     311             :  *     (parameter_name_n ....))
     312             :  *
     313             :  * Example:
     314             :  *
     315             :  *   (rsa
     316             :  *     (nbits 4:2048)
     317             :  *     (rsa-use-e 2:41))
     318             :  *
     319             :  * On success the value for nbits is stored at R_E.  If no rsa-use-e
     320             :  * parameter is found, the function returns success and stores 65537 at
     321             :  * R_E.  For parsing errors the function returns an error code and
     322             :  * stores 0 at R_E.
     323             :  */
     324             : gpg_err_code_t
     325           0 : _gcry_pk_util_get_rsa_use_e (gcry_sexp_t list, unsigned long *r_e)
     326             : {
     327             :   char buf[50];
     328             :   const char *s;
     329             :   size_t n;
     330             : 
     331           0 :   *r_e = 0;
     332             : 
     333           0 :   list = sexp_find_token (list, "rsa-use-e", 0);
     334           0 :   if (!list)
     335             :     {
     336           0 :       *r_e = 65537; /* Not given, use the value generated by old versions. */
     337           0 :       return 0;
     338             :     }
     339             : 
     340           0 :   s = sexp_nth_data (list, 1, &n);
     341           0 :   if (!s || n >= DIM (buf) - 1 )
     342             :     {
     343             :       /* No value or value too large.  */
     344           0 :       sexp_release (list);
     345           0 :       return GPG_ERR_INV_OBJ;
     346             :     }
     347           0 :   memcpy (buf, s, n);
     348           0 :   buf[n] = 0;
     349           0 :   *r_e = strtoul (buf, NULL, 0);
     350           0 :   sexp_release (list);
     351           0 :   return 0;
     352             : }
     353             : 
     354             : 
     355             : /* Parse a "sig-val" s-expression and store the inner parameter list at
     356             :    R_PARMS.  ALGO_NAMES is used to verify that the algorithm in
     357             :    "sig-val" is valid.  Returns 0 on success and stores a new list at
     358             :    R_PARMS which must be freed by the caller.  On error R_PARMS is set
     359             :    to NULL and an error code returned.  If R_ECCFLAGS is not NULL flag
     360             :    values are set into it; as of now they are only used with ecc
     361             :    algorithms.  */
     362             : gpg_err_code_t
     363           0 : _gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig, const char **algo_names,
     364             :                                gcry_sexp_t *r_parms, int *r_eccflags)
     365             : {
     366             :   gpg_err_code_t rc;
     367           0 :   gcry_sexp_t l1 = NULL;
     368           0 :   gcry_sexp_t l2 = NULL;
     369           0 :   char *name = NULL;
     370             :   int i;
     371             : 
     372           0 :   *r_parms = NULL;
     373           0 :   if (r_eccflags)
     374           0 :     *r_eccflags = 0;
     375             : 
     376             :   /* Extract the signature value.  */
     377           0 :   l1 = sexp_find_token (s_sig, "sig-val", 0);
     378           0 :   if (!l1)
     379             :     {
     380           0 :       rc = GPG_ERR_INV_OBJ; /* Does not contain a signature value object.  */
     381           0 :       goto leave;
     382             :     }
     383             : 
     384           0 :   l2 = sexp_nth (l1, 1);
     385           0 :   if (!l2)
     386             :     {
     387           0 :       rc = GPG_ERR_NO_OBJ;   /* No cadr for the sig object.  */
     388           0 :       goto leave;
     389             :     }
     390           0 :   name = sexp_nth_string (l2, 0);
     391           0 :   if (!name)
     392             :     {
     393           0 :       rc = GPG_ERR_INV_OBJ;  /* Invalid structure of object.  */
     394           0 :       goto leave;
     395             :     }
     396           0 :   else if (!strcmp (name, "flags"))
     397             :     {
     398             :       /* Skip a "flags" parameter and look again for the algorithm
     399             :          name.  This is not used but here just for the sake of
     400             :          consistent S-expressions we need to handle it. */
     401           0 :       sexp_release (l2);
     402           0 :       l2 = sexp_nth (l1, 2);
     403           0 :       if (!l2)
     404             :         {
     405           0 :           rc = GPG_ERR_INV_OBJ;
     406           0 :           goto leave;
     407             :         }
     408           0 :       xfree (name);
     409           0 :       name = sexp_nth_string (l2, 0);
     410           0 :       if (!name)
     411             :         {
     412           0 :           rc = GPG_ERR_INV_OBJ;  /* Invalid structure of object.  */
     413           0 :           goto leave;
     414             :         }
     415             :     }
     416             : 
     417           0 :   for (i=0; algo_names[i]; i++)
     418           0 :     if (!stricmp (name, algo_names[i]))
     419           0 :       break;
     420           0 :   if (!algo_names[i])
     421             :     {
     422           0 :       rc = GPG_ERR_CONFLICT; /* "sig-val" uses an unexpected algo. */
     423           0 :       goto leave;
     424             :     }
     425           0 :   if (r_eccflags)
     426             :     {
     427           0 :       if (!strcmp (name, "eddsa"))
     428           0 :         *r_eccflags = PUBKEY_FLAG_EDDSA;
     429           0 :       if (!strcmp (name, "gost"))
     430           0 :         *r_eccflags = PUBKEY_FLAG_GOST;
     431             :     }
     432             : 
     433           0 :   *r_parms = l2;
     434           0 :   l2 = NULL;
     435           0 :   rc = 0;
     436             : 
     437             :  leave:
     438           0 :   xfree (name);
     439           0 :   sexp_release (l2);
     440           0 :   sexp_release (l1);
     441           0 :   return rc;
     442             : }
     443             : 
     444             : 
     445             : /* Parse a "enc-val" s-expression and store the inner parameter list
     446             :    at R_PARMS.  ALGO_NAMES is used to verify that the algorithm in
     447             :    "enc-val" is valid.  Returns 0 on success and stores a new list at
     448             :    R_PARMS which must be freed by the caller.  On error R_PARMS is set
     449             :    to NULL and an error code returned.  If R_ECCFLAGS is not NULL flag
     450             :    values are set into it; as of now they are only used with ecc
     451             :    algorithms.
     452             : 
     453             :      (enc-val
     454             :        [(flags [raw, pkcs1, oaep, no-blinding])]
     455             :        [(hash-algo <algo>)]
     456             :        [(label <label>)]
     457             :         (<algo>
     458             :           (<param_name1> <mpi>)
     459             :           ...
     460             :           (<param_namen> <mpi>)))
     461             : 
     462             :    HASH-ALGO and LABEL are specific to OAEP.  CTX will be updated with
     463             :    encoding information.  */
     464             : gpg_err_code_t
     465           0 : _gcry_pk_util_preparse_encval (gcry_sexp_t sexp, const char **algo_names,
     466             :                                gcry_sexp_t *r_parms,
     467             :                                struct pk_encoding_ctx *ctx)
     468             : {
     469           0 :   gcry_err_code_t rc = 0;
     470           0 :   gcry_sexp_t l1 = NULL;
     471           0 :   gcry_sexp_t l2 = NULL;
     472           0 :   char *name = NULL;
     473             :   size_t n;
     474           0 :   int parsed_flags = 0;
     475             :   int i;
     476             : 
     477           0 :   *r_parms = NULL;
     478             : 
     479             :   /* Check that the first element is valid.  */
     480           0 :   l1 = sexp_find_token (sexp, "enc-val" , 0);
     481           0 :   if (!l1)
     482             :     {
     483           0 :       rc = GPG_ERR_INV_OBJ; /* Does not contain an encrypted value object.  */
     484           0 :       goto leave;
     485             :     }
     486             : 
     487           0 :   l2 = sexp_nth (l1, 1);
     488           0 :   if (!l2)
     489             :     {
     490           0 :       rc = GPG_ERR_NO_OBJ;  /* No cadr for the data object.  */
     491           0 :       goto leave;
     492             :     }
     493             : 
     494             :   /* Extract identifier of sublist.  */
     495           0 :   name = sexp_nth_string (l2, 0);
     496           0 :   if (!name)
     497             :     {
     498           0 :       rc = GPG_ERR_INV_OBJ; /* Invalid structure of object.  */
     499           0 :       goto leave;
     500             :     }
     501             : 
     502           0 :   if (!strcmp (name, "flags"))
     503             :     {
     504             :       const char *s;
     505             : 
     506             :       /* There is a flags element - process it.  */
     507           0 :       rc = _gcry_pk_util_parse_flaglist (l2, &parsed_flags, &ctx->encoding);
     508           0 :       if (rc)
     509           0 :         goto leave;
     510           0 :       if (ctx->encoding == PUBKEY_ENC_PSS)
     511             :         {
     512           0 :           rc = GPG_ERR_CONFLICT;
     513           0 :           goto leave;
     514             :         }
     515             : 
     516             :       /* Get the OAEP parameters HASH-ALGO and LABEL, if any. */
     517           0 :       if (ctx->encoding == PUBKEY_ENC_OAEP)
     518             :         {
     519             :           /* Get HASH-ALGO. */
     520           0 :           sexp_release (l2);
     521           0 :           l2 = sexp_find_token (l1, "hash-algo", 0);
     522           0 :           if (l2)
     523             :             {
     524           0 :               s = sexp_nth_data (l2, 1, &n);
     525           0 :               if (!s)
     526           0 :                 rc = GPG_ERR_NO_OBJ;
     527             :               else
     528             :                 {
     529           0 :                   ctx->hash_algo = get_hash_algo (s, n);
     530           0 :                   if (!ctx->hash_algo)
     531           0 :                     rc = GPG_ERR_DIGEST_ALGO;
     532             :                 }
     533           0 :               if (rc)
     534           0 :                 goto leave;
     535             :             }
     536             : 
     537             :           /* Get LABEL. */
     538           0 :           sexp_release (l2);
     539           0 :           l2 = sexp_find_token (l1, "label", 0);
     540           0 :           if (l2)
     541             :             {
     542           0 :               s = sexp_nth_data (l2, 1, &n);
     543           0 :               if (!s)
     544           0 :                 rc = GPG_ERR_NO_OBJ;
     545           0 :               else if (n > 0)
     546             :                 {
     547           0 :                   ctx->label = xtrymalloc (n);
     548           0 :                   if (!ctx->label)
     549           0 :                     rc = gpg_err_code_from_syserror ();
     550             :                   else
     551             :                     {
     552           0 :                       memcpy (ctx->label, s, n);
     553           0 :                       ctx->labellen = n;
     554             :                     }
     555             :                 }
     556           0 :               if (rc)
     557           0 :                 goto leave;
     558             :             }
     559             :         }
     560             : 
     561             :       /* Get the next which has the actual data - skip HASH-ALGO and LABEL. */
     562           0 :       for (i = 2; (sexp_release (l2), l2 = sexp_nth (l1, i)); i++)
     563             :         {
     564           0 :           s = sexp_nth_data (l2, 0, &n);
     565           0 :           if (!(n == 9 && !memcmp (s, "hash-algo", 9))
     566           0 :               && !(n == 5 && !memcmp (s, "label", 5))
     567           0 :               && !(n == 15 && !memcmp (s, "random-override", 15)))
     568             :             break;
     569             :         }
     570           0 :       if (!l2)
     571             :         {
     572           0 :           rc = GPG_ERR_NO_OBJ; /* No cadr for the data object. */
     573           0 :           goto leave;
     574             :         }
     575             : 
     576             :       /* Extract sublist identifier.  */
     577           0 :       xfree (name);
     578           0 :       name = sexp_nth_string (l2, 0);
     579           0 :       if (!name)
     580             :         {
     581           0 :           rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
     582           0 :           goto leave;
     583             :         }
     584             :     }
     585             :   else /* No flags - flag as legacy structure.  */
     586           0 :     parsed_flags |= PUBKEY_FLAG_LEGACYRESULT;
     587             : 
     588           0 :   for (i=0; algo_names[i]; i++)
     589           0 :     if (!stricmp (name, algo_names[i]))
     590           0 :       break;
     591           0 :   if (!algo_names[i])
     592             :     {
     593           0 :       rc = GPG_ERR_CONFLICT; /* "enc-val" uses an unexpected algo. */
     594           0 :       goto leave;
     595             :     }
     596             : 
     597           0 :   *r_parms = l2;
     598           0 :   l2 = NULL;
     599           0 :   ctx->flags |= parsed_flags;
     600           0 :   rc = 0;
     601             : 
     602             :  leave:
     603           0 :   xfree (name);
     604           0 :   sexp_release (l2);
     605           0 :   sexp_release (l1);
     606           0 :   return rc;
     607             : }
     608             : 
     609             : 
     610             : /* Initialize an encoding context.  */
     611             : void
     612           0 : _gcry_pk_util_init_encoding_ctx (struct pk_encoding_ctx *ctx,
     613             :                                  enum pk_operation op,
     614             :                                  unsigned int nbits)
     615             : {
     616           0 :   ctx->op = op;
     617           0 :   ctx->nbits = nbits;
     618           0 :   ctx->encoding = PUBKEY_ENC_UNKNOWN;
     619           0 :   ctx->flags = 0;
     620           0 :   if (fips_mode ())
     621             :     {
     622           0 :       ctx->hash_algo = GCRY_MD_SHA256;
     623             :     }
     624             :   else
     625             :     {
     626           0 :       ctx->hash_algo = GCRY_MD_SHA1;
     627             :     }
     628           0 :   ctx->label = NULL;
     629           0 :   ctx->labellen = 0;
     630           0 :   ctx->saltlen = 20;
     631           0 :   ctx->verify_cmp = NULL;
     632           0 :   ctx->verify_arg = NULL;
     633           0 : }
     634             : 
     635             : /* Free a context initialzied by _gcry_pk_util_init_encoding_ctx.  */
     636             : void
     637           0 : _gcry_pk_util_free_encoding_ctx (struct pk_encoding_ctx *ctx)
     638             : {
     639           0 :   xfree (ctx->label);
     640           0 : }
     641             : 
     642             : 
     643             : /* Take the hash value and convert into an MPI, suitable for
     644             :    passing to the low level functions.  We currently support the
     645             :    old style way of passing just a MPI and the modern interface which
     646             :    allows to pass flags so that we can choose between raw and pkcs1
     647             :    padding - may be more padding options later.
     648             : 
     649             :    (<mpi>)
     650             :    or
     651             :    (data
     652             :     [(flags [raw, direct, pkcs1, oaep, pss, no-blinding, rfc6979, eddsa])]
     653             :     [(hash <algo> <value>)]
     654             :     [(value <text>)]
     655             :     [(hash-algo <algo>)]
     656             :     [(label <label>)]
     657             :     [(salt-length <length>)]
     658             :     [(random-override <data>)]
     659             :    )
     660             : 
     661             :    Either the VALUE or the HASH element must be present for use
     662             :    with signatures.  VALUE is used for encryption.
     663             : 
     664             :    HASH-ALGO is specific to OAEP and EDDSA.
     665             : 
     666             :    LABEL is specific to OAEP.
     667             : 
     668             :    SALT-LENGTH is for PSS it is limited to 16384 bytes.
     669             : 
     670             :    RANDOM-OVERRIDE is used to replace random nonces for regression
     671             :    testing.  */
     672             : gcry_err_code_t
     673           0 : _gcry_pk_util_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
     674             :                            struct pk_encoding_ctx *ctx)
     675             : {
     676           0 :   gcry_err_code_t rc = 0;
     677             :   gcry_sexp_t ldata, lhash, lvalue;
     678             :   size_t n;
     679             :   const char *s;
     680           0 :   int unknown_flag = 0;
     681           0 :   int parsed_flags = 0;
     682             : 
     683           0 :   *ret_mpi = NULL;
     684           0 :   ldata = sexp_find_token (input, "data", 0);
     685           0 :   if (!ldata)
     686             :     { /* assume old style */
     687           0 :       *ret_mpi = sexp_nth_mpi (input, 0, 0);
     688           0 :       return *ret_mpi ? GPG_ERR_NO_ERROR : GPG_ERR_INV_OBJ;
     689             :     }
     690             : 
     691             :   /* See whether there is a flags list.  */
     692             :   {
     693           0 :     gcry_sexp_t lflags = sexp_find_token (ldata, "flags", 0);
     694           0 :     if (lflags)
     695             :       {
     696           0 :         if (_gcry_pk_util_parse_flaglist (lflags,
     697             :                                           &parsed_flags, &ctx->encoding))
     698           0 :           unknown_flag = 1;
     699           0 :         sexp_release (lflags);
     700             :       }
     701             :   }
     702             : 
     703           0 :   if (ctx->encoding == PUBKEY_ENC_UNKNOWN)
     704           0 :     ctx->encoding = PUBKEY_ENC_RAW; /* default to raw */
     705             : 
     706             :   /* Get HASH or MPI */
     707           0 :   lhash = sexp_find_token (ldata, "hash", 0);
     708           0 :   lvalue = lhash? NULL : sexp_find_token (ldata, "value", 0);
     709             : 
     710           0 :   if (!(!lhash ^ !lvalue))
     711           0 :     rc = GPG_ERR_INV_OBJ; /* none or both given */
     712           0 :   else if (unknown_flag)
     713           0 :     rc = GPG_ERR_INV_FLAG;
     714           0 :   else if (ctx->encoding == PUBKEY_ENC_RAW
     715           0 :            && (parsed_flags & PUBKEY_FLAG_EDDSA))
     716           0 :     {
     717             :       /* Prepare for EdDSA.  */
     718             :       gcry_sexp_t list;
     719             :       void *value;
     720             :       size_t valuelen;
     721             : 
     722           0 :       if (!lvalue)
     723             :         {
     724           0 :           rc = GPG_ERR_INV_OBJ;
     725           0 :           goto leave;
     726             :         }
     727             :       /* Get HASH-ALGO. */
     728           0 :       list = sexp_find_token (ldata, "hash-algo", 0);
     729           0 :       if (list)
     730             :         {
     731           0 :           s = sexp_nth_data (list, 1, &n);
     732           0 :           if (!s)
     733           0 :             rc = GPG_ERR_NO_OBJ;
     734             :           else
     735             :             {
     736           0 :               ctx->hash_algo = get_hash_algo (s, n);
     737           0 :               if (!ctx->hash_algo)
     738           0 :                 rc = GPG_ERR_DIGEST_ALGO;
     739             :             }
     740           0 :           sexp_release (list);
     741             :         }
     742             :       else
     743           0 :         rc = GPG_ERR_INV_OBJ;
     744           0 :       if (rc)
     745           0 :         goto leave;
     746             : 
     747             :       /* Get VALUE.  */
     748           0 :       value = sexp_nth_buffer (lvalue, 1, &valuelen);
     749           0 :       if (!value)
     750             :         {
     751             :           /* We assume that a zero length message is meant by
     752             :              "(value)".  This is commonly used by test vectors.  Note
     753             :              that S-expression do not allow zero length items. */
     754           0 :           valuelen = 0;
     755           0 :           value = xtrymalloc (1);
     756           0 :           if (!value)
     757           0 :             rc = gpg_err_code_from_syserror ();
     758             :         }
     759           0 :       else if ((valuelen * 8) < valuelen)
     760             :         {
     761           0 :           xfree (value);
     762           0 :           rc = GPG_ERR_TOO_LARGE;
     763             :         }
     764           0 :       if (rc)
     765           0 :         goto leave;
     766             : 
     767             :       /* Note that mpi_set_opaque takes ownership of VALUE.  */
     768           0 :       *ret_mpi = mpi_set_opaque (NULL, value, valuelen*8);
     769             :     }
     770           0 :   else if (ctx->encoding == PUBKEY_ENC_RAW && lhash
     771           0 :            && ((parsed_flags & PUBKEY_FLAG_RAW_FLAG)
     772           0 :                || (parsed_flags & PUBKEY_FLAG_RFC6979)))
     773             :     {
     774             :       /* Raw encoding along with a hash element.  This is commonly
     775             :          used for DSA.  For better backward error compatibility we
     776             :          allow this only if either the rfc6979 flag has been given or
     777             :          the raw flags was explicitly given.  */
     778           0 :       if (sexp_length (lhash) != 3)
     779           0 :         rc = GPG_ERR_INV_OBJ;
     780           0 :       else if ( !(s=sexp_nth_data (lhash, 1, &n)) || !n )
     781           0 :         rc = GPG_ERR_INV_OBJ;
     782             :       else
     783             :         {
     784             :           void *value;
     785             :           size_t valuelen;
     786             : 
     787           0 :           ctx->hash_algo = get_hash_algo (s, n);
     788           0 :           if (!ctx->hash_algo)
     789           0 :             rc = GPG_ERR_DIGEST_ALGO;
     790           0 :           else if (!(value=sexp_nth_buffer (lhash, 2, &valuelen)))
     791           0 :             rc = GPG_ERR_INV_OBJ;
     792           0 :           else if ((valuelen * 8) < valuelen)
     793             :             {
     794           0 :               xfree (value);
     795           0 :               rc = GPG_ERR_TOO_LARGE;
     796             :             }
     797             :           else
     798           0 :             *ret_mpi = mpi_set_opaque (NULL, value, valuelen*8);
     799             :         }
     800             :     }
     801           0 :   else if (ctx->encoding == PUBKEY_ENC_RAW && lvalue)
     802             :     {
     803             :       /* RFC6969 may only be used with the a hash value and not the
     804             :          MPI based value.  */
     805           0 :       if (parsed_flags & PUBKEY_FLAG_RFC6979)
     806             :         {
     807           0 :           rc = GPG_ERR_CONFLICT;
     808           0 :           goto leave;
     809             :         }
     810             : 
     811             :       /* Get the value */
     812           0 :       *ret_mpi = sexp_nth_mpi (lvalue, 1, GCRYMPI_FMT_USG);
     813           0 :       if (!*ret_mpi)
     814           0 :         rc = GPG_ERR_INV_OBJ;
     815             :     }
     816           0 :   else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lvalue
     817           0 :            && ctx->op == PUBKEY_OP_ENCRYPT)
     818           0 :     {
     819             :       const void * value;
     820             :       size_t valuelen;
     821             :       gcry_sexp_t list;
     822           0 :       void *random_override = NULL;
     823           0 :       size_t random_override_len = 0;
     824             : 
     825           0 :       if ( !(value=sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
     826           0 :         rc = GPG_ERR_INV_OBJ;
     827             :       else
     828             :         {
     829             :           /* Get optional RANDOM-OVERRIDE.  */
     830           0 :           list = sexp_find_token (ldata, "random-override", 0);
     831           0 :           if (list)
     832             :             {
     833           0 :               s = sexp_nth_data (list, 1, &n);
     834           0 :               if (!s)
     835           0 :                 rc = GPG_ERR_NO_OBJ;
     836           0 :               else if (n > 0)
     837             :                 {
     838           0 :                   random_override = xtrymalloc (n);
     839           0 :                   if (!random_override)
     840           0 :                     rc = gpg_err_code_from_syserror ();
     841             :                   else
     842             :                     {
     843           0 :                       memcpy (random_override, s, n);
     844           0 :                       random_override_len = n;
     845             :                     }
     846             :                 }
     847           0 :               sexp_release (list);
     848           0 :               if (rc)
     849           0 :                 goto leave;
     850             :             }
     851             : 
     852           0 :           rc = _gcry_rsa_pkcs1_encode_for_enc (ret_mpi, ctx->nbits,
     853             :                                                value, valuelen,
     854             :                                                random_override,
     855             :                                                random_override_len);
     856           0 :           xfree (random_override);
     857             :         }
     858             :     }
     859           0 :   else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lhash
     860           0 :            && (ctx->op == PUBKEY_OP_SIGN || ctx->op == PUBKEY_OP_VERIFY))
     861             :     {
     862           0 :       if (sexp_length (lhash) != 3)
     863           0 :         rc = GPG_ERR_INV_OBJ;
     864           0 :       else if ( !(s=sexp_nth_data (lhash, 1, &n)) || !n )
     865           0 :         rc = GPG_ERR_INV_OBJ;
     866             :       else
     867             :         {
     868             :           const void * value;
     869             :           size_t valuelen;
     870             : 
     871           0 :           ctx->hash_algo = get_hash_algo (s, n);
     872             : 
     873           0 :           if (!ctx->hash_algo)
     874           0 :             rc = GPG_ERR_DIGEST_ALGO;
     875           0 :           else if ( !(value=sexp_nth_data (lhash, 2, &valuelen))
     876           0 :                     || !valuelen )
     877           0 :             rc = GPG_ERR_INV_OBJ;
     878             :           else
     879           0 :             rc = _gcry_rsa_pkcs1_encode_for_sig (ret_mpi, ctx->nbits,
     880             :                                                  value, valuelen,
     881             :                                                  ctx->hash_algo);
     882             :         }
     883             :     }
     884           0 :   else if (ctx->encoding == PUBKEY_ENC_PKCS1_RAW && lvalue
     885           0 :            && (ctx->op == PUBKEY_OP_SIGN || ctx->op == PUBKEY_OP_VERIFY))
     886           0 :     {
     887             :       const void * value;
     888             :       size_t valuelen;
     889             : 
     890           0 :       if (sexp_length (lvalue) != 2)
     891           0 :         rc = GPG_ERR_INV_OBJ;
     892           0 :       else if ( !(value=sexp_nth_data (lvalue, 1, &valuelen))
     893           0 :                 || !valuelen )
     894           0 :         rc = GPG_ERR_INV_OBJ;
     895             :       else
     896           0 :         rc = _gcry_rsa_pkcs1_encode_raw_for_sig (ret_mpi, ctx->nbits,
     897             :                                                  value, valuelen);
     898             :     }
     899           0 :   else if (ctx->encoding == PUBKEY_ENC_OAEP && lvalue
     900           0 :            && ctx->op == PUBKEY_OP_ENCRYPT)
     901           0 :     {
     902             :       const void * value;
     903             :       size_t valuelen;
     904             : 
     905           0 :       if ( !(value=sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
     906           0 :         rc = GPG_ERR_INV_OBJ;
     907             :       else
     908             :         {
     909             :           gcry_sexp_t list;
     910           0 :           void *random_override = NULL;
     911           0 :           size_t random_override_len = 0;
     912             : 
     913             :           /* Get HASH-ALGO. */
     914           0 :           list = sexp_find_token (ldata, "hash-algo", 0);
     915           0 :           if (list)
     916             :             {
     917           0 :               s = sexp_nth_data (list, 1, &n);
     918           0 :               if (!s)
     919           0 :                 rc = GPG_ERR_NO_OBJ;
     920             :               else
     921             :                 {
     922           0 :                   ctx->hash_algo = get_hash_algo (s, n);
     923           0 :                   if (!ctx->hash_algo)
     924           0 :                     rc = GPG_ERR_DIGEST_ALGO;
     925             :                 }
     926           0 :               sexp_release (list);
     927           0 :               if (rc)
     928           0 :                 goto leave;
     929             :             }
     930             : 
     931             :           /* Get LABEL. */
     932           0 :           list = sexp_find_token (ldata, "label", 0);
     933           0 :           if (list)
     934             :             {
     935           0 :               s = sexp_nth_data (list, 1, &n);
     936           0 :               if (!s)
     937           0 :                 rc = GPG_ERR_NO_OBJ;
     938           0 :               else if (n > 0)
     939             :                 {
     940           0 :                   ctx->label = xtrymalloc (n);
     941           0 :                   if (!ctx->label)
     942           0 :                     rc = gpg_err_code_from_syserror ();
     943             :                   else
     944             :                     {
     945           0 :                       memcpy (ctx->label, s, n);
     946           0 :                       ctx->labellen = n;
     947             :                     }
     948             :                 }
     949           0 :               sexp_release (list);
     950           0 :               if (rc)
     951           0 :                 goto leave;
     952             :             }
     953             :           /* Get optional RANDOM-OVERRIDE.  */
     954           0 :           list = sexp_find_token (ldata, "random-override", 0);
     955           0 :           if (list)
     956             :             {
     957           0 :               s = sexp_nth_data (list, 1, &n);
     958           0 :               if (!s)
     959           0 :                 rc = GPG_ERR_NO_OBJ;
     960           0 :               else if (n > 0)
     961             :                 {
     962           0 :                   random_override = xtrymalloc (n);
     963           0 :                   if (!random_override)
     964           0 :                     rc = gpg_err_code_from_syserror ();
     965             :                   else
     966             :                     {
     967           0 :                       memcpy (random_override, s, n);
     968           0 :                       random_override_len = n;
     969             :                     }
     970             :                 }
     971           0 :               sexp_release (list);
     972           0 :               if (rc)
     973           0 :                 goto leave;
     974             :             }
     975             : 
     976           0 :           rc = _gcry_rsa_oaep_encode (ret_mpi, ctx->nbits, ctx->hash_algo,
     977             :                                       value, valuelen,
     978           0 :                                       ctx->label, ctx->labellen,
     979             :                                       random_override, random_override_len);
     980             : 
     981           0 :           xfree (random_override);
     982             :         }
     983             :     }
     984           0 :   else if (ctx->encoding == PUBKEY_ENC_PSS && lhash
     985           0 :            && ctx->op == PUBKEY_OP_SIGN)
     986             :     {
     987           0 :       if (sexp_length (lhash) != 3)
     988           0 :         rc = GPG_ERR_INV_OBJ;
     989           0 :       else if ( !(s=sexp_nth_data (lhash, 1, &n)) || !n )
     990           0 :         rc = GPG_ERR_INV_OBJ;
     991             :       else
     992             :         {
     993             :           const void * value;
     994             :           size_t valuelen;
     995           0 :           void *random_override = NULL;
     996           0 :           size_t random_override_len = 0;
     997             : 
     998           0 :           ctx->hash_algo = get_hash_algo (s, n);
     999             : 
    1000           0 :           if (!ctx->hash_algo)
    1001           0 :             rc = GPG_ERR_DIGEST_ALGO;
    1002           0 :           else if ( !(value=sexp_nth_data (lhash, 2, &valuelen))
    1003           0 :                     || !valuelen )
    1004           0 :             rc = GPG_ERR_INV_OBJ;
    1005             :           else
    1006             :             {
    1007             :               gcry_sexp_t list;
    1008             : 
    1009             :               /* Get SALT-LENGTH. */
    1010           0 :               list = sexp_find_token (ldata, "salt-length", 0);
    1011           0 :               if (list)
    1012             :                 {
    1013           0 :                   s = sexp_nth_data (list, 1, &n);
    1014           0 :                   if (!s)
    1015             :                     {
    1016           0 :                       rc = GPG_ERR_NO_OBJ;
    1017           0 :                       goto leave;
    1018             :                     }
    1019           0 :                   ctx->saltlen = (unsigned int)strtoul (s, NULL, 10);
    1020           0 :                   sexp_release (list);
    1021             :                 }
    1022             : 
    1023             :               /* Get optional RANDOM-OVERRIDE.  */
    1024           0 :               list = sexp_find_token (ldata, "random-override", 0);
    1025           0 :               if (list)
    1026             :                 {
    1027           0 :                   s = sexp_nth_data (list, 1, &n);
    1028           0 :                   if (!s)
    1029           0 :                     rc = GPG_ERR_NO_OBJ;
    1030           0 :                   else if (n > 0)
    1031             :                     {
    1032           0 :                       random_override = xtrymalloc (n);
    1033           0 :                       if (!random_override)
    1034           0 :                         rc = gpg_err_code_from_syserror ();
    1035             :                       else
    1036             :                         {
    1037           0 :                           memcpy (random_override, s, n);
    1038           0 :                           random_override_len = n;
    1039             :                         }
    1040             :                     }
    1041           0 :                   sexp_release (list);
    1042           0 :                   if (rc)
    1043           0 :                     goto leave;
    1044             :                 }
    1045             : 
    1046             :               /* Encode the data.  (NBITS-1 is due to 8.1.1, step 1.) */
    1047           0 :               rc = _gcry_rsa_pss_encode (ret_mpi, ctx->nbits - 1,
    1048             :                                          ctx->hash_algo,
    1049           0 :                                          value, valuelen, ctx->saltlen,
    1050             :                                          random_override, random_override_len);
    1051             : 
    1052           0 :               xfree (random_override);
    1053             :             }
    1054             :         }
    1055             :     }
    1056           0 :   else if (ctx->encoding == PUBKEY_ENC_PSS && lhash
    1057           0 :            && ctx->op == PUBKEY_OP_VERIFY)
    1058             :     {
    1059           0 :       if (sexp_length (lhash) != 3)
    1060           0 :         rc = GPG_ERR_INV_OBJ;
    1061           0 :       else if ( !(s=sexp_nth_data (lhash, 1, &n)) || !n )
    1062           0 :         rc = GPG_ERR_INV_OBJ;
    1063             :       else
    1064             :         {
    1065           0 :           ctx->hash_algo = get_hash_algo (s, n);
    1066             : 
    1067           0 :           if (!ctx->hash_algo)
    1068           0 :             rc = GPG_ERR_DIGEST_ALGO;
    1069             :           else
    1070             :             {
    1071             :               gcry_sexp_t list;
    1072             :               /* Get SALT-LENGTH. */
    1073           0 :               list = sexp_find_token (ldata, "salt-length", 0);
    1074           0 :               if (list)
    1075             :                 {
    1076             :                   unsigned long ul;
    1077             : 
    1078           0 :                   s = sexp_nth_data (list, 1, &n);
    1079           0 :                   if (!s)
    1080             :                     {
    1081           0 :                       rc = GPG_ERR_NO_OBJ;
    1082           0 :                       sexp_release (list);
    1083           0 :                       goto leave;
    1084             :                     }
    1085           0 :                   ul = strtoul (s, NULL, 10);
    1086           0 :                   if (ul > 16384)
    1087             :                     {
    1088           0 :                       rc = GPG_ERR_TOO_LARGE;
    1089           0 :                       sexp_release (list);
    1090           0 :                       goto leave;
    1091             :                     }
    1092           0 :                   ctx->saltlen = ul;
    1093           0 :                   sexp_release (list);
    1094             :                 }
    1095             : 
    1096           0 :               *ret_mpi = sexp_nth_mpi (lhash, 2, GCRYMPI_FMT_USG);
    1097           0 :               if (!*ret_mpi)
    1098           0 :                 rc = GPG_ERR_INV_OBJ;
    1099           0 :               ctx->verify_cmp = pss_verify_cmp;
    1100           0 :               ctx->verify_arg = *ret_mpi;
    1101             :             }
    1102             :         }
    1103             :     }
    1104             :   else
    1105           0 :     rc = GPG_ERR_CONFLICT;
    1106             : 
    1107             :  leave:
    1108           0 :   sexp_release (ldata);
    1109           0 :   sexp_release (lhash);
    1110           0 :   sexp_release (lvalue);
    1111             : 
    1112           0 :   if (!rc)
    1113           0 :     ctx->flags = parsed_flags;
    1114             :   else
    1115             :     {
    1116           0 :       xfree (ctx->label);
    1117           0 :       ctx->label = NULL;
    1118             :     }
    1119             : 
    1120           0 :   return rc;
    1121             : }

Generated by: LCOV version 1.12