1 /*
2  *  Copyright (c) 2016, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file includes definitions for Thread security material generation.
32  */
33 
34 #ifndef KEY_MANAGER_HPP_
35 #define KEY_MANAGER_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <stdint.h>
40 
41 #include <openthread/dataset.h>
42 #include <openthread/platform/crypto.h>
43 
44 #include "common/as_core_type.hpp"
45 #include "common/clearable.hpp"
46 #include "common/encoding.hpp"
47 #include "common/equatable.hpp"
48 #include "common/locator.hpp"
49 #include "common/non_copyable.hpp"
50 #include "common/random.hpp"
51 #include "common/timer.hpp"
52 #include "crypto/hmac_sha256.hpp"
53 #include "mac/mac_types.hpp"
54 #include "thread/mle_types.hpp"
55 
56 namespace ot {
57 
58 /**
59  * @addtogroup core-security
60  *
61  * @brief
62  *   This module includes definitions for Thread security material generation.
63  *
64  * @{
65  */
66 
67 /**
68  * This class represents Security Policy Rotation and Flags.
69  *
70  */
71 class SecurityPolicy : public otSecurityPolicy, public Equatable<SecurityPolicy>
72 {
73 public:
74     /**
75      * Offset between the Thread Version and the Version-threshold valid for Routing.
76      *
77      */
78     static constexpr uint8_t kVersionThresholdOffsetVersion = 3;
79 
80     static constexpr uint16_t kMinKeyRotationTime     = 1;   ///< The minimum Key Rotation Time in hours.
81     static constexpr uint16_t kDefaultKeyRotationTime = 672; ///< Default Key Rotation Time (in unit of hours).
82 
83     /**
84      * This constructor initializes the object with default Key Rotation Time
85      * and Security Policy Flags.
86      *
87      */
SecurityPolicy(void)88     SecurityPolicy(void) { SetToDefault(); }
89 
90     /**
91      * This method sets the Security Policy to default values.
92      *
93      */
94     void SetToDefault(void);
95 
96     /**
97      * This method sets the Security Policy Flags.
98      *
99      * @param[in]  aFlags        The Security Policy Flags.
100      * @param[in]  aFlagsLength  The length of the Security Policy Flags, 1 byte for
101      *                           Thread 1.1 devices, and 2 bytes for Thread 1.2 or higher.
102      *
103      */
104     void SetFlags(const uint8_t *aFlags, uint8_t aFlagsLength);
105 
106     /**
107      * This method returns the Security Policy Flags.
108      *
109      * @param[out] aFlags        A pointer to the Security Policy Flags buffer.
110      * @param[in]  aFlagsLength  The length of the Security Policy Flags buffer.
111      *
112      */
113     void GetFlags(uint8_t *aFlags, uint8_t aFlagsLength) const;
114 
115 private:
116     static constexpr uint8_t kDefaultFlags                   = 0xff;
117     static constexpr uint8_t kObtainNetworkKeyMask           = 1 << 7;
118     static constexpr uint8_t kNativeCommissioningMask        = 1 << 6;
119     static constexpr uint8_t kRoutersMask                    = 1 << 5;
120     static constexpr uint8_t kExternalCommissioningMask      = 1 << 4;
121     static constexpr uint8_t kBeaconsMask                    = 1 << 3;
122     static constexpr uint8_t kCommercialCommissioningMask    = 1 << 2;
123     static constexpr uint8_t kAutonomousEnrollmentMask       = 1 << 1;
124     static constexpr uint8_t kNetworkKeyProvisioningMask     = 1 << 0;
125     static constexpr uint8_t kTobleLinkMask                  = 1 << 7;
126     static constexpr uint8_t kNonCcmRoutersMask              = 1 << 6;
127     static constexpr uint8_t kReservedMask                   = 0x38;
128     static constexpr uint8_t kVersionThresholdForRoutingMask = 0x07;
129 
130     void SetToDefaultFlags(void);
131 };
132 
133 /**
134  * This class represents a Thread Network Key.
135  *
136  */
137 OT_TOOL_PACKED_BEGIN
138 class NetworkKey : public otNetworkKey, public Equatable<NetworkKey>, public Clearable<NetworkKey>
139 {
140 public:
141     static constexpr uint8_t kSize = OT_NETWORK_KEY_SIZE; ///< Size of the Thread Network Key (in bytes).
142 
143 #if !OPENTHREAD_RADIO
144     /**
145      * This method generates a cryptographically secure random sequence to populate the Thread Network Key.
146      *
147      * @retval kErrorNone     Successfully generated a random Thread Network Key.
148      * @retval kErrorFailed   Failed to generate random sequence.
149      *
150      */
GenerateRandom(void)151     Error GenerateRandom(void) { return Random::Crypto::FillBuffer(m8, sizeof(m8)); }
152 #endif
153 
154 } OT_TOOL_PACKED_END;
155 
156 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
157 /**
158  * Provides a representation for Network Key reference.
159  *
160  */
161 typedef otNetworkKeyRef NetworkKeyRef;
162 #endif
163 
164 /**
165  * This class represents a Thread Pre-Shared Key for the Commissioner (PSKc).
166  *
167  */
168 OT_TOOL_PACKED_BEGIN
169 class Pskc : public otPskc, public Equatable<Pskc>, public Clearable<Pskc>
170 {
171 public:
172     static constexpr uint8_t kSize = OT_PSKC_MAX_SIZE; ///< Size (number of bytes) of the PSKc.
173 
174 #if !OPENTHREAD_RADIO
175     /**
176      * This method generates a cryptographically secure random sequence to populate the Thread PSKc.
177      *
178      * @retval kErrorNone  Successfully generated a random Thread PSKc.
179      *
180      */
GenerateRandom(void)181     Error GenerateRandom(void) { return Random::Crypto::FillBuffer(m8, sizeof(m8)); }
182 #endif
183 } OT_TOOL_PACKED_END;
184 
185 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
186 /**
187  * Provides a representation for Network Key reference.
188  *
189  */
190 typedef otPskcRef PskcRef;
191 #endif
192 
193 /**
194  *
195  * This class represents a Key Encryption Key (KEK).
196  *
197  */
198 typedef Mac::Key Kek;
199 
200 /**
201  *
202  * This class represents a Key Material for Key Encryption Key (KEK).
203  *
204  */
205 typedef Mac::KeyMaterial KekKeyMaterial;
206 
207 /**
208  * This class defines Thread Key Manager.
209  *
210  */
211 class KeyManager : public InstanceLocator, private NonCopyable
212 {
213 public:
214     /**
215      * This constructor initializes the object.
216      *
217      * @param[in]  aInstance     A reference to the OpenThread instance.
218      *
219      */
220     explicit KeyManager(Instance &aInstance);
221 
222     /**
223      * This method starts KeyManager rotation timer and sets guard timer to initial value.
224      *
225      */
226     void Start(void);
227 
228     /**
229      * This method stops KeyManager timers.
230      *
231      */
232     void Stop(void);
233 
234     /**
235      * This method gets the Thread Network Key.
236      *
237      * @param[out] aNetworkKey   A reference to a `NetworkKey` to output the Thread Network Key.
238      *
239      */
240     void GetNetworkKey(NetworkKey &aNetworkKey) const;
241 
242     /**
243      * This method sets the Thread Network Key.
244      *
245      * @param[in]  aNetworkKey        A Thread Network Key.
246      *
247      */
248     void SetNetworkKey(const NetworkKey &aNetworkKey);
249 
250 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
251     /**
252      * This method returns a Key Ref to Thread Network Key.
253      *
254      * @returns A key reference to the Thread Network Key.
255      *
256      */
GetNetworkKeyRef(void) const257     NetworkKeyRef GetNetworkKeyRef(void) const { return mNetworkKeyRef; }
258 
259     /**
260      * This method sets the Thread Network Key using Key Reference.
261      *
262      * @param[in]  aKeyRef        Reference to Thread Network Key.
263      *
264      */
265     void SetNetworkKeyRef(NetworkKeyRef aKeyRef);
266 #endif
267 
268     /**
269      * This method indicates whether the PSKc is configured.
270      *
271      * A value of all zeros indicates that the PSKc is not configured.
272      *
273      * @retval TRUE  if the PSKc is configured.
274      * @retval FALSE if the PSKc is not not configured.
275      *
276      */
IsPskcSet(void) const277     bool IsPskcSet(void) const { return mIsPskcSet; }
278 
279     /**
280      * This method gets the PKSc.
281      *
282      * @param[out] aPskc  A reference to a `Pskc` to return the PSKc.
283      *
284      */
285     void GetPskc(Pskc &aPskc) const;
286 
287     /**
288      * This method sets the PSKc.
289      *
290      * @param[in]  aPskc    A reference to the PSKc.
291      *
292      */
293     void SetPskc(const Pskc &aPskc);
294 
295 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
296     /**
297      * This method returns a Key Ref to PSKc.
298      *
299      * @returns A key reference to the PSKc.
300      *
301      */
GetPskcRef(void) const302     const PskcRef &GetPskcRef(void) const { return mPskcRef; }
303 
304     /**
305      * This method sets the PSKc as a Key reference.
306      *
307      * @param[in]  aPskc    A reference to the PSKc.
308      *
309      */
310     void SetPskcRef(PskcRef aKeyRef);
311 #endif
312 
313     /**
314      * This method returns the current key sequence value.
315      *
316      * @returns The current key sequence value.
317      *
318      */
GetCurrentKeySequence(void) const319     uint32_t GetCurrentKeySequence(void) const { return mKeySequence; }
320 
321     /**
322      * This method sets the current key sequence value.
323      *
324      * @param[in]  aKeySequence  The key sequence value.
325      *
326      */
327     void SetCurrentKeySequence(uint32_t aKeySequence);
328 
329 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
330     /**
331      * This method returns the current MAC key for TREL radio link.
332      *
333      * @returns The current TREL MAC key.
334      *
335      */
GetCurrentTrelMacKey(void) const336     const Mac::KeyMaterial &GetCurrentTrelMacKey(void) const { return mTrelKey; }
337 
338     /**
339      * This method returns a temporary MAC key for TREL radio link computed from the given key sequence.
340      *
341      * @param[in]  aKeySequence  The key sequence value.
342      *
343      * @returns The temporary TREL MAC key.
344      *
345      */
346     const Mac::KeyMaterial &GetTemporaryTrelMacKey(uint32_t aKeySequence);
347 #endif
348 
349     /**
350      * This method returns the current MLE key Material.
351      *
352      * @returns The current MLE key.
353      *
354      */
GetCurrentMleKey(void) const355     const Mle::KeyMaterial &GetCurrentMleKey(void) const { return mMleKey; }
356 
357     /**
358      * This method returns a temporary MLE key Material computed from the given key sequence.
359      *
360      * @param[in]  aKeySequence  The key sequence value.
361      *
362      * @returns The temporary MLE key.
363      *
364      */
365     const Mle::KeyMaterial &GetTemporaryMleKey(uint32_t aKeySequence);
366 
367 #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
368     /**
369      * This method returns the current MAC Frame Counter value for 15.4 radio link.
370      *
371      * @returns The current MAC Frame Counter value.
372      *
373      */
Get154MacFrameCounter(void) const374     uint32_t Get154MacFrameCounter(void) const { return mMacFrameCounters.Get154(); }
375 #endif
376 
377 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
378     /**
379      * This method returns the current MAC Frame Counter value for TREL radio link.
380      *
381      * @returns The current MAC Frame Counter value for TREL radio link.
382      *
383      */
GetTrelMacFrameCounter(void) const384     uint32_t GetTrelMacFrameCounter(void) const { return mMacFrameCounters.GetTrel(); }
385 
386     /**
387      * This method increments the current MAC Frame Counter value for TREL radio link.
388      *
389      */
390     void IncrementTrelMacFrameCounter(void);
391 #endif
392 
393     /**
394      * This method gets the maximum MAC Frame Counter among all supported radio links.
395      *
396      * @return The maximum MAC frame Counter among all supported radio links.
397      *
398      */
GetMaximumMacFrameCounter(void) const399     uint32_t GetMaximumMacFrameCounter(void) const { return mMacFrameCounters.GetMaximum(); }
400 
401     /**
402      * This method sets the current MAC Frame Counter value for all radio links.
403      *
404      * @param[in] aFrameCounter  The MAC Frame Counter value.
405      * @param[in] aSetIfLarger   If `true`, set only if the new value @p aFrameCounter is larger than current value.
406      *                           If `false`, set the new value independent of the current value.
407 
408      */
409     void SetAllMacFrameCounters(uint32_t aFrameCounter, bool aSetIfLarger);
410 
411     /**
412      * This method sets the MAC Frame Counter value which is stored in non-volatile memory.
413      *
414      * @param[in]  aStoredMacFrameCounter  The stored MAC Frame Counter value.
415      *
416      */
SetStoredMacFrameCounter(uint32_t aStoredMacFrameCounter)417     void SetStoredMacFrameCounter(uint32_t aStoredMacFrameCounter) { mStoredMacFrameCounter = aStoredMacFrameCounter; }
418 
419     /**
420      * This method returns the current MLE Frame Counter value.
421      *
422      * @returns The current MLE Frame Counter value.
423      *
424      */
GetMleFrameCounter(void) const425     uint32_t GetMleFrameCounter(void) const { return mMleFrameCounter; }
426 
427     /**
428      * This method sets the current MLE Frame Counter value.
429      *
430      * @param[in]  aMleFrameCounter  The MLE Frame Counter value.
431      *
432      */
SetMleFrameCounter(uint32_t aMleFrameCounter)433     void SetMleFrameCounter(uint32_t aMleFrameCounter) { mMleFrameCounter = aMleFrameCounter; }
434 
435     /**
436      * This method sets the MLE Frame Counter value which is stored in non-volatile memory.
437      *
438      * @param[in]  aStoredMleFrameCounter  The stored MLE Frame Counter value.
439      *
440      */
SetStoredMleFrameCounter(uint32_t aStoredMleFrameCounter)441     void SetStoredMleFrameCounter(uint32_t aStoredMleFrameCounter) { mStoredMleFrameCounter = aStoredMleFrameCounter; }
442 
443     /**
444      * This method increments the current MLE Frame Counter value.
445      *
446      */
447     void IncrementMleFrameCounter(void);
448 
449     /**
450      * This method returns the KEK as `KekKeyMaterial`
451      *
452      * @returns The KEK as `KekKeyMaterial`.
453      *
454      */
GetKek(void) const455     const KekKeyMaterial &GetKek(void) const { return mKek; }
456 
457     /**
458      * This method retrieves the KEK as literal `Kek` key.
459      *
460      * @param[out] aKek  A reference to a `Kek` to output the retrieved KEK.
461      *
462      */
ExtractKek(Kek & aKek)463     void ExtractKek(Kek &aKek) { mKek.ExtractKey(aKek); }
464 
465     /**
466      * This method sets the KEK.
467      *
468      * @param[in]  aKek  A KEK.
469      *
470      */
471     void SetKek(const Kek &aKek);
472 
473     /**
474      * This method sets the KEK.
475      *
476      * @param[in]  aKekBytes  A pointer to the KEK bytes.
477      *
478      */
SetKek(const uint8_t * aKekBytes)479     void SetKek(const uint8_t *aKekBytes) { SetKek(*reinterpret_cast<const Kek *>(aKekBytes)); }
480 
481     /**
482      * This method returns the current KEK Frame Counter value.
483      *
484      * @returns The current KEK Frame Counter value.
485      *
486      */
GetKekFrameCounter(void) const487     uint32_t GetKekFrameCounter(void) const { return mKekFrameCounter; }
488 
489     /**
490      * This method increments the current KEK Frame Counter value.
491      *
492      */
IncrementKekFrameCounter(void)493     void IncrementKekFrameCounter(void) { mKekFrameCounter++; }
494 
495     /**
496      * This method returns the KeySwitchGuardTime.
497      *
498      * The KeySwitchGuardTime is the time interval during which key rotation procedure is prevented.
499      *
500      * @returns The KeySwitchGuardTime value in hours.
501      *
502      */
GetKeySwitchGuardTime(void) const503     uint32_t GetKeySwitchGuardTime(void) const { return mKeySwitchGuardTime; }
504 
505     /**
506      * This method sets the KeySwitchGuardTime.
507      *
508      * The KeySwitchGuardTime is the time interval during which key rotation procedure is prevented.
509      *
510      * @param[in]  aKeySwitchGuardTime  The KeySwitchGuardTime value in hours.
511      *
512      */
SetKeySwitchGuardTime(uint32_t aKeySwitchGuardTime)513     void SetKeySwitchGuardTime(uint32_t aKeySwitchGuardTime) { mKeySwitchGuardTime = aKeySwitchGuardTime; }
514 
515     /**
516      * This method returns the Security Policy.
517      *
518      * The Security Policy specifies Key Rotation Time and network administrator preferences
519      * for which security-related operations are allowed or disallowed.
520      *
521      * @returns The SecurityPolicy.
522      *
523      */
GetSecurityPolicy(void) const524     const SecurityPolicy &GetSecurityPolicy(void) const { return mSecurityPolicy; }
525 
526     /**
527      * This method sets the Security Policy.
528      *
529      * The Security Policy specifies Key Rotation Time and network administrator preferences
530      * for which security-related operations are allowed or disallowed.
531      *
532      * @param[in]  aSecurityPolicy  The Security Policy.
533      *
534      */
535     void SetSecurityPolicy(const SecurityPolicy &aSecurityPolicy);
536 
537     /**
538      * This method updates the MAC keys and MLE key.
539      *
540      */
541     void UpdateKeyMaterial(void);
542 
543     /**
544      * This method handles MAC frame counter changes (callback from `SubMac` for 15.4 security frame change).
545      *
546      * This is called to indicate the @p aMacFrameCounter value is now used.
547      *
548      * @param[in]  aMacFrameCounter     The 15.4 link MAC frame counter value.
549      *
550      */
551     void MacFrameCounterUsed(uint32_t aMacFrameCounter);
552 
553 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
554     /**
555      * This method destroys all the volatile mac keys stored in PSA ITS.
556      *
557      */
558     void DestroyTemporaryKeys(void);
559 
560     /**
561      * This method destroys all the persistent keys stored in PSA ITS.
562      *
563      */
564     void DestroyPersistentKeys(void);
565 #endif
566 
567 private:
568     static constexpr uint32_t kDefaultKeySwitchGuardTime = 624;
569     static constexpr uint32_t kOneHourIntervalInMsec     = 3600u * 1000u;
570     static constexpr bool     kExportableMacKeys         = OPENTHREAD_CONFIG_PLATFORM_MAC_KEYS_EXPORTABLE_ENABLE;
571 
572     OT_TOOL_PACKED_BEGIN
573     struct Keys
574     {
575         Mle::Key mMleKey;
576         Mac::Key mMacKey;
577     } OT_TOOL_PACKED_END;
578 
579     union HashKeys
580     {
581         Crypto::HmacSha256::Hash mHash;
582         Keys                     mKeys;
583 
GetMleKey(void) const584         const Mle::Key &GetMleKey(void) const { return mKeys.mMleKey; }
GetMacKey(void) const585         const Mac::Key &GetMacKey(void) const { return mKeys.mMacKey; }
586     };
587 
588     void ComputeKeys(uint32_t aKeySequence, HashKeys &aHashKeys) const;
589 
590 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
591     void ComputeTrelKey(uint32_t aKeySequence, Mac::Key &aKey) const;
592 #endif
593 
594     void StartKeyRotationTimer(void);
595     void HandleKeyRotationTimer(void);
596 
597 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
598     void StoreNetworkKey(const NetworkKey &aNetworkKey, bool aOverWriteExisting);
599     void StorePskc(const Pskc &aPskc);
600 #endif
601 
602     void ResetFrameCounters(void);
603 
604     using RotationTimer = TimerMilliIn<KeyManager, &KeyManager::HandleKeyRotationTimer>;
605 
606     static const uint8_t kThreadString[];
607 
608 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
609     static const uint8_t kHkdfExtractSaltString[];
610     static const uint8_t kTrelInfoString[];
611 #endif
612 
613 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
614     NetworkKeyRef mNetworkKeyRef;
615 #else
616     NetworkKey mNetworkKey;
617 #endif
618 
619     uint32_t         mKeySequence;
620     Mle::KeyMaterial mMleKey;
621     Mle::KeyMaterial mTemporaryMleKey;
622 
623 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
624     Mac::KeyMaterial mTrelKey;
625     Mac::KeyMaterial mTemporaryTrelKey;
626 #endif
627 
628     Mac::LinkFrameCounters mMacFrameCounters;
629     uint32_t               mMleFrameCounter;
630     uint32_t               mStoredMacFrameCounter;
631     uint32_t               mStoredMleFrameCounter;
632 
633     uint32_t      mHoursSinceKeyRotation;
634     uint32_t      mKeySwitchGuardTime;
635     bool          mKeySwitchGuardEnabled;
636     RotationTimer mKeyRotationTimer;
637 
638 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
639     PskcRef mPskcRef;
640 #else
641     Pskc       mPskc;
642 #endif
643 
644     KekKeyMaterial mKek;
645     uint32_t       mKekFrameCounter;
646 
647     SecurityPolicy mSecurityPolicy;
648     bool           mIsPskcSet : 1;
649 };
650 
651 /**
652  * @}
653  */
654 
655 DefineCoreType(otSecurityPolicy, SecurityPolicy);
656 DefineCoreType(otNetworkKey, NetworkKey);
657 DefineCoreType(otPskc, Pskc);
658 
659 } // namespace ot
660 
661 #endif // KEY_MANAGER_HPP_
662