1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
//------------------------------------------------------------------------------
// <copyright file="MachineKeyMasterKeyProvider.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Security.Cryptography {
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Web.Configuration;
// Gets this application's master keys from the <machineKey> element,
// optionally going against the auto-gen keys if AutoGenerate has been specified.
internal sealed class MachineKeyMasterKeyProvider : IMasterKeyProvider {
private const int AUTOGEN_ENCRYPTION_OFFSET = 0;
private const int AUTOGEN_ENCRYPTION_KEYLENGTH = 256; // AES-256
private const int AUTOGEN_VALIDATION_OFFSET = AUTOGEN_ENCRYPTION_KEYLENGTH;
private const int AUTOGEN_VALIDATION_KEYLENGTH = 256; // HMACSHA256
private const string AUTOGEN_KEYDERIVATION_PRIMARYPURPOSE = "MachineKeyDerivation";
private const string AUTOGEN_KEYDERIVATION_ISOLATEAPPS_SPECIFICPURPOSE = "IsolateApps";
private const string AUTOGEN_KEYDERIVATION_ISOLATEBYAPPID_SPECIFICPURPOSE = "IsolateByAppId";
private string _applicationId;
private string _applicationName;
private CryptographicKey _autogenKeys;
private CryptographicKey _encryptionKey;
private KeyDerivationFunction _keyDerivationFunction;
private readonly MachineKeySection _machineKeySection;
private CryptographicKey _validationKey;
// the only required parameter is 'machineKeySection'; other parameters are just used for unit testing
internal MachineKeyMasterKeyProvider(MachineKeySection machineKeySection, string applicationId = null, string applicationName = null, CryptographicKey autogenKeys = null, KeyDerivationFunction keyDerivationFunction = null) {
_machineKeySection = machineKeySection;
_applicationId = applicationId;
_applicationName = applicationName;
_autogenKeys = autogenKeys;
_keyDerivationFunction = keyDerivationFunction;
}
internal string ApplicationName {
get {
if (_applicationName == null) {
_applicationName = HttpRuntime.AppDomainAppVirtualPath ?? Process.GetCurrentProcess().MainModule.ModuleName;
}
return _applicationName;
}
}
internal string ApplicationId {
get {
if (_applicationId == null) {
_applicationId = HttpRuntime.AppDomainAppId;
}
return _applicationId;
}
}
internal CryptographicKey AutogenKeys {
get {
if (_autogenKeys == null) {
_autogenKeys = new CryptographicKey(HttpRuntime.s_autogenKeys);
}
return _autogenKeys;
}
}
internal KeyDerivationFunction KeyDerivationFunction {
get {
if (_keyDerivationFunction == null) {
_keyDerivationFunction = SP800_108.DeriveKey;
}
return _keyDerivationFunction;
}
}
private static void AddSpecificPurposeString(IList<string> specificPurposes, string key, string value) {
specificPurposes.Add(key + ": " + value);
}
// Generates 'cryptographicKey' from either the raw key material specified in config
// or from the auto-generated key found in the system registry, optionally performing
// subkey derivation.
private CryptographicKey GenerateCryptographicKey(string configAttributeName, string configAttributeValue, int autogenKeyOffset, int autogenKeyCount, string errorResourceString) {
byte[] keyMaterial = CryptoUtil.HexToBinary(configAttributeValue);
// If <machineKey> contained a valid key, just use it verbatim.
if (keyMaterial != null && keyMaterial.Length > 0) {
return new CryptographicKey(keyMaterial);
}
// Otherwise, we need to generate it.
bool autoGenerate = false;
bool isolateApps = false;
bool isolateByAppId = false;
if (configAttributeValue != null) {
foreach (string flag in configAttributeValue.Split(',')) {
switch (flag) {
case "AutoGenerate":
autoGenerate = true;
break;
case "IsolateApps":
isolateApps = true;
break;
case "IsolateByAppId":
isolateByAppId = true;
break;
default:
throw ConfigUtil.MakeConfigurationErrorsException(
message: SR.GetString(errorResourceString),
configProperty: _machineKeySection.ElementInformation.Properties[configAttributeName]);
}
}
}
if (!autoGenerate) {
// at the absolute minimum, we must be configured to autogenerate
throw ConfigUtil.MakeConfigurationErrorsException(
message: SR.GetString(errorResourceString),
configProperty: _machineKeySection.ElementInformation.Properties[configAttributeName]);
}
// The key should be a subset of the auto-generated key (which is a concatenation of several keys)
CryptographicKey keyDerivationKey = AutogenKeys.ExtractBits(autogenKeyOffset, autogenKeyCount);
List<string> specificPurposes = new List<string>();
if (isolateApps) {
// Use the application name to derive a new cryptographic key
AddSpecificPurposeString(specificPurposes, AUTOGEN_KEYDERIVATION_ISOLATEAPPS_SPECIFICPURPOSE, ApplicationName);
}
if (isolateByAppId) {
// Use the application ID to derive a new cryptographic key
AddSpecificPurposeString(specificPurposes, AUTOGEN_KEYDERIVATION_ISOLATEBYAPPID_SPECIFICPURPOSE, ApplicationId);
}
// Don't use the auto-gen key directly; derive a new one based on specified parameters.
Purpose purpose = new Purpose(AUTOGEN_KEYDERIVATION_PRIMARYPURPOSE, specificPurposes.ToArray());
return KeyDerivationFunction(keyDerivationKey, purpose);
}
public CryptographicKey GetEncryptionKey() {
if (_encryptionKey == null) {
_encryptionKey = GenerateCryptographicKey(
configAttributeName: "decryptionKey",
configAttributeValue: _machineKeySection.DecryptionKey,
autogenKeyOffset: AUTOGEN_ENCRYPTION_OFFSET,
autogenKeyCount: AUTOGEN_ENCRYPTION_KEYLENGTH,
errorResourceString: SR.Invalid_decryption_key);
}
return _encryptionKey;
}
public CryptographicKey GetValidationKey() {
if (_validationKey == null) {
_validationKey = GenerateCryptographicKey(
configAttributeName: "validationKey",
configAttributeValue: _machineKeySection.ValidationKey,
autogenKeyOffset: AUTOGEN_VALIDATION_OFFSET,
autogenKeyCount: AUTOGEN_VALIDATION_KEYLENGTH,
errorResourceString: SR.Invalid_validation_key);
}
return _validationKey;
}
}
}
|