Annotation of embedaddon/strongswan/src/libstrongswan/credentials/keys/signature_params.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2017 Tobias Brunner
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify it
! 6: * under the terms of the GNU General Public License as published by the
! 7: * Free Software Foundation; either version 2 of the License, or (at your
! 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 9: *
! 10: * This program is distributed in the hope that it will be useful, but
! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 13: * for more details.
! 14: */
! 15:
! 16: #include "signature_params.h"
! 17:
! 18: #include <asn1/oid.h>
! 19: #include <asn1/asn1_parser.h>
! 20:
! 21: /*
! 22: * Described in header
! 23: */
! 24: bool rsa_pss_params_set_salt_len(rsa_pss_params_t *params, size_t modbits)
! 25: {
! 26: size_t hash_len;
! 27:
! 28: if (params->salt_len < 0)
! 29: {
! 30: hash_len = hasher_hash_size(params->hash);
! 31: if (!hash_len)
! 32: {
! 33: return FALSE;
! 34: }
! 35:
! 36: switch (params->salt_len)
! 37: {
! 38: case RSA_PSS_SALT_LEN_DEFAULT:
! 39: params->salt_len = hash_len;
! 40: break;
! 41: case RSA_PSS_SALT_LEN_MAX:
! 42: if (modbits)
! 43: {
! 44: /* emBits = modBits - 1 */
! 45: modbits -= 1;
! 46: /* emLen = ceil(emBits/8) */
! 47: modbits = (modbits+7) / BITS_PER_BYTE;
! 48: /* account for 0x01 separator in DB, 0xbc trailing byte */
! 49: params->salt_len = max(0, (ssize_t)(modbits - hash_len - 2));
! 50: break;
! 51: }
! 52: return FALSE;
! 53: default:
! 54: return FALSE;
! 55: }
! 56: }
! 57: return TRUE;
! 58: }
! 59:
! 60: /**
! 61: * Compare two signature schemes and their parameters
! 62: */
! 63: static bool compare_params(signature_params_t *a, signature_params_t *b,
! 64: bool strict)
! 65: {
! 66: if (!a && !b)
! 67: {
! 68: return TRUE;
! 69: }
! 70: if (!a || !b)
! 71: {
! 72: return FALSE;
! 73: }
! 74: if (a->scheme != b->scheme)
! 75: {
! 76: return FALSE;
! 77: }
! 78: if (!a->params && !b->params)
! 79: {
! 80: return TRUE;
! 81: }
! 82: if (a->params && b->params)
! 83: {
! 84: switch (a->scheme)
! 85: {
! 86: case SIGN_RSA_EMSA_PSS:
! 87: {
! 88: rsa_pss_params_t *pss_a = a->params, *pss_b = b->params;
! 89:
! 90: return pss_a->hash == pss_b->hash &&
! 91: pss_a->mgf1_hash == pss_b->mgf1_hash &&
! 92: (!strict || pss_a->salt_len == pss_b->salt_len);
! 93: }
! 94: default:
! 95: break;
! 96: }
! 97: }
! 98: return FALSE;
! 99: }
! 100:
! 101: /*
! 102: * Described in header
! 103: */
! 104: bool signature_params_equal(signature_params_t *a, signature_params_t *b)
! 105: {
! 106: return compare_params(a, b, TRUE);
! 107: }
! 108:
! 109: /*
! 110: * Described in header
! 111: */
! 112: bool signature_params_comply(signature_params_t *c, signature_params_t *s)
! 113: { /* the salt is variable, so it does not necessarily have to be the same */
! 114: return compare_params(c, s, FALSE);
! 115: }
! 116:
! 117: /*
! 118: * Described in header
! 119: */
! 120: signature_params_t *signature_params_clone(signature_params_t *this)
! 121: {
! 122: signature_params_t *clone;
! 123:
! 124: if (!this)
! 125: {
! 126: return NULL;
! 127: }
! 128:
! 129: INIT(clone,
! 130: .scheme = this->scheme,
! 131: );
! 132: if (this->params)
! 133: {
! 134: switch (this->scheme)
! 135: {
! 136: case SIGN_RSA_EMSA_PSS:
! 137: {
! 138: rsa_pss_params_t *pss, *pss_clone;
! 139:
! 140: pss = this->params;
! 141: INIT(pss_clone,
! 142: .hash = pss->hash,
! 143: .mgf1_hash = pss->mgf1_hash,
! 144: .salt_len = pss->salt_len,
! 145: /* ignore salt as only used for unit tests */
! 146: );
! 147: clone->params = pss_clone;
! 148: break;
! 149: }
! 150: default:
! 151: break;
! 152: }
! 153: }
! 154: return clone;
! 155: }
! 156:
! 157: /*
! 158: * Described in header
! 159: */
! 160: void signature_params_destroy(signature_params_t *this)
! 161: {
! 162: if (this)
! 163: {
! 164: free(this->params);
! 165: free(this);
! 166: }
! 167: }
! 168:
! 169: /*
! 170: * Described in header
! 171: */
! 172: void signature_params_clear(signature_params_t *this)
! 173: {
! 174: if (this)
! 175: {
! 176: free(this->params);
! 177: this->params = NULL;
! 178: this->scheme = SIGN_UNKNOWN;
! 179: }
! 180: }
! 181:
! 182: /*
! 183: * Described in header
! 184: */
! 185: bool signature_params_parse(chunk_t asn1, int level0,
! 186: signature_params_t *params)
! 187: {
! 188: chunk_t parameters = chunk_empty;
! 189: int oid;
! 190:
! 191: oid = asn1_parse_algorithmIdentifier(asn1, level0, ¶meters);
! 192: params->scheme = signature_scheme_from_oid(oid);
! 193: switch (params->scheme)
! 194: {
! 195: case SIGN_UNKNOWN:
! 196: return FALSE;
! 197: case SIGN_RSA_EMSA_PSS:
! 198: {
! 199: rsa_pss_params_t *pss = malloc_thing(rsa_pss_params_t);
! 200:
! 201: if (!rsa_pss_params_parse(parameters, level0+1, pss))
! 202: {
! 203: DBG1(DBG_IKE, "failed parsing RSASSA-PSS parameters");
! 204: free(pss);
! 205: return FALSE;
! 206: }
! 207: params->params = pss;
! 208: break;
! 209: }
! 210: default:
! 211: params->params = NULL;
! 212: break;
! 213: }
! 214: return TRUE;
! 215: }
! 216:
! 217: /*
! 218: * Described in header
! 219: */
! 220: bool signature_params_build(signature_params_t *params, chunk_t *asn1)
! 221: {
! 222: chunk_t parameters = chunk_empty;
! 223: int oid;
! 224:
! 225: oid = signature_scheme_to_oid(params->scheme);
! 226: if (oid == OID_UNKNOWN)
! 227: {
! 228: return FALSE;
! 229: }
! 230: if (params->scheme == SIGN_RSA_EMSA_PSS &&
! 231: !rsa_pss_params_build(params->params, ¶meters))
! 232: {
! 233: return FALSE;
! 234: }
! 235: if (parameters.len)
! 236: {
! 237: *asn1 = asn1_algorithmIdentifier_params(oid, parameters);
! 238: }
! 239: else
! 240: {
! 241: *asn1 = asn1_algorithmIdentifier(oid);
! 242: }
! 243: return TRUE;
! 244: }
! 245:
! 246: /**
! 247: * ASN.1 definition of RSASSA-PSS-params
! 248: */
! 249: static const asn1Object_t RSASSAPSSParamsObjects[] = {
! 250: { 0, "RSASSA-PSS-params", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
! 251: { 1, "DEFAULT SHA-1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 1 */
! 252: { 2, "hashAlgorithm", ASN1_EOC, ASN1_RAW }, /* 2 */
! 253: { 1, "DEFAULT MGF1SHA1", ASN1_CONTEXT_C_1, ASN1_DEF }, /* 3 */
! 254: { 2, "maskGenAlgorithm",ASN1_EOC, ASN1_RAW }, /* 4 */
! 255: { 1, "DEFAULT 20", ASN1_CONTEXT_C_2, ASN1_DEF }, /* 5 */
! 256: { 2, "saltLength", ASN1_INTEGER, ASN1_BODY }, /* 6 */
! 257: { 1, "DEFAULT 1", ASN1_CONTEXT_C_3, ASN1_DEF }, /* 7 */
! 258: { 2, "trailerField", ASN1_INTEGER, ASN1_BODY }, /* 8 */
! 259: { 0, "exit", ASN1_EOC, ASN1_EXIT }
! 260: };
! 261: #define RSASSA_PSS_PARAMS_HASH_ALG 2
! 262: #define RSASSA_PSS_PARAMS_MGF_ALG 4
! 263: #define RSASSA_PSS_PARAMS_SALT_LEN 6
! 264: #define RSASSA_PSS_PARAMS_TRAILER 8
! 265:
! 266: /*
! 267: * Described in header
! 268: */
! 269: bool rsa_pss_params_parse(chunk_t asn1, int level0, rsa_pss_params_t *params)
! 270: {
! 271: asn1_parser_t *parser;
! 272: chunk_t object;
! 273: int objectID, alg;
! 274: bool success = FALSE;
! 275:
! 276: params->hash = HASH_SHA1;
! 277: params->mgf1_hash = HASH_SHA1;
! 278: params->salt_len = HASH_SIZE_SHA1;
! 279:
! 280: parser = asn1_parser_create(RSASSAPSSParamsObjects, asn1);
! 281: parser->set_top_level(parser, level0);
! 282:
! 283: while (parser->iterate(parser, &objectID, &object))
! 284: {
! 285: u_int level = parser->get_level(parser)+1;
! 286:
! 287: switch (objectID)
! 288: {
! 289: case RSASSA_PSS_PARAMS_HASH_ALG:
! 290: if (object.len)
! 291: {
! 292: alg = asn1_parse_algorithmIdentifier(object, level, NULL);
! 293: params->hash = hasher_algorithm_from_oid(alg);
! 294: if (params->hash == HASH_UNKNOWN)
! 295: {
! 296: goto end;
! 297: }
! 298: }
! 299: break;
! 300: case RSASSA_PSS_PARAMS_MGF_ALG:
! 301: if (object.len)
! 302: {
! 303: chunk_t hash = chunk_empty;
! 304:
! 305: alg = asn1_parse_algorithmIdentifier(object, level, &hash);
! 306: if (alg != OID_MGF1)
! 307: {
! 308: goto end;
! 309: }
! 310: if (!hash.len)
! 311: {
! 312: goto end;
! 313: }
! 314: alg = asn1_parse_algorithmIdentifier(hash, level+1, NULL);
! 315: params->mgf1_hash = hasher_algorithm_from_oid(alg);
! 316: if (params->mgf1_hash == HASH_UNKNOWN)
! 317: {
! 318: goto end;
! 319: }
! 320: }
! 321: break;
! 322: case RSASSA_PSS_PARAMS_SALT_LEN:
! 323: if (object.len)
! 324: {
! 325: params->salt_len = (size_t)asn1_parse_integer_uint64(object);
! 326: }
! 327: break;
! 328: case RSASSA_PSS_PARAMS_TRAILER:
! 329: if (object.len && (object.len != 1 || *object.ptr != 1))
! 330: {
! 331: goto end;
! 332: }
! 333: break;
! 334: default:
! 335: break;
! 336: }
! 337: }
! 338: success = parser->success(parser);
! 339:
! 340: end:
! 341: parser->destroy(parser);
! 342: return success;
! 343: }
! 344:
! 345: /*
! 346: * Described in header
! 347: */
! 348: bool rsa_pss_params_build(rsa_pss_params_t *params, chunk_t *asn1)
! 349: {
! 350: chunk_t hash = chunk_empty, mgf = chunk_empty, slen = chunk_empty;
! 351: int alg;
! 352:
! 353: if (params->hash != HASH_SHA1)
! 354: { /* with SHA-1 we MUST omit the field */
! 355: alg = hasher_algorithm_to_oid(params->hash);
! 356: if (alg == OID_UNKNOWN)
! 357: {
! 358: return FALSE;
! 359: }
! 360: hash = asn1_algorithmIdentifier(alg);
! 361: }
! 362: if (params->mgf1_hash != HASH_SHA1)
! 363: { /* with MGF1-SHA1 we MUST omit the field */
! 364: alg = hasher_algorithm_to_oid(params->mgf1_hash);
! 365: if (alg == OID_UNKNOWN)
! 366: {
! 367: chunk_free(&hash);
! 368: return FALSE;
! 369: }
! 370: mgf = asn1_algorithmIdentifier_params(OID_MGF1,
! 371: asn1_algorithmIdentifier(alg));
! 372: }
! 373: if (params->salt_len < 0)
! 374: {
! 375: chunk_free(&hash);
! 376: chunk_free(&mgf);
! 377: return FALSE;
! 378: }
! 379: else if (params->salt_len != HASH_SIZE_SHA1)
! 380: {
! 381: slen = asn1_integer("m", asn1_integer_from_uint64(params->salt_len));
! 382: }
! 383: *asn1 = asn1_wrap(ASN1_SEQUENCE, "mmm",
! 384: hash.len ? asn1_wrap(ASN1_CONTEXT_C_0, "m", hash) : chunk_empty,
! 385: mgf.len ? asn1_wrap(ASN1_CONTEXT_C_1, "m", mgf) : chunk_empty,
! 386: slen.len ? asn1_wrap(ASN1_CONTEXT_C_2, "m", slen) : chunk_empty);
! 387: return TRUE;
! 388: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>