File: MachineKeyMasterKeyProvider.cs

package info (click to toggle)
mono 5.18.0.240%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 1,253,216 kB
  • sloc: cs: 10,925,936; xml: 2,804,987; ansic: 643,970; cpp: 120,384; perl: 59,272; asm: 21,383; sh: 20,162; makefile: 18,157; python: 4,715; pascal: 924; sql: 859; sed: 16; php: 1
file content (174 lines) | stat: -rw-r--r-- 7,975 bytes parent folder | download | duplicates (7)
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;
        }

    }
}